From 0987171280e2c250d39b0dbc72eca37a0b44481a Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sun, 19 Oct 2008 11:47:03 -0400
Subject: [PATCH 001/103] - Added support for "task stop " command, that
removes the start time from a task. - Updated documentation accordingly.
---
ChangeLog | 1 +
html/advanced.html | 5 +++++
html/task.html | 1 +
html/usage.html | 1 +
src/command.cpp | 30 ++++++++++++++++++++++++++++++
src/parse.cpp | 1 +
src/task.cpp | 12 ++++++------
src/task.h | 1 +
8 files changed, 46 insertions(+), 6 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index c2b641218..52f729398 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,6 +5,7 @@
+ Removed deprecated TUTORIAL file.
+ Removed "usage" command, and support for "command.logging" configuration
variable.
+ + "task stop" can now remove the start time from a started task.
------ old releases ------------------------------
diff --git a/html/advanced.html b/html/advanced.html
index 30fc4a436..1aeb75361 100644
--- a/html/advanced.html
+++ b/html/advanced.html
@@ -157,6 +157,11 @@ ID Project Pri Due Active Age Description
"task start ..." command was run, as shown above.
+ % task stop <id>
+
+ Marks a task as inactive, by removing the start time.
+
+
% task overdue
Simply lists all the task that have a due date that is past, in
diff --git a/html/task.html b/html/task.html
index b4ba90991..3118b1ea4 100644
--- a/html/task.html
+++ b/html/task.html
@@ -99,6 +99,7 @@
Removed deprecated TUTORIAL file.
Removed "usage" command, and support for "command.logging" configuration
variable.
+
"task stop" can remove the start time from a started task.
diff --git a/html/usage.html b/html/usage.html
index 92b7b1d88..7c42de3a5 100644
--- a/html/usage.html
+++ b/html/usage.html
@@ -44,6 +44,7 @@
task undelete ID
task info ID
task start ID
+ task stop ID
task done ID
task undo ID
task projects
diff --git a/src/command.cpp b/src/command.cpp
index 6d0b70508..b444b9515 100644
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -441,6 +441,36 @@ void handleStart (TDB& tdb, T& task, Config& conf)
throw std::string ("Task not found.");
}
+////////////////////////////////////////////////////////////////////////////////
+void handleStop (TDB& tdb, T& task, Config& conf)
+{
+ std::vector all;
+ tdb.pendingT (all);
+
+ std::vector ::iterator it;
+ for (it = all.begin (); it != all.end (); ++it)
+ {
+ if (it->getId () == task.getId ())
+ {
+ T original (*it);
+
+ if (original.getAttribute ("start") != "")
+ {
+ original.removeAttribute ("start");
+ original.setId (task.getId ());
+ tdb.modifyT (original);
+
+ nag (tdb, task, conf);
+ return;
+ }
+ else
+ std::cout << "Task " << task.getId () << " not started." << std::endl;
+ }
+ }
+
+ throw std::string ("Task not found.");
+}
+
////////////////////////////////////////////////////////////////////////////////
void handleDone (TDB& tdb, T& task, Config& conf)
{
diff --git a/src/parse.cpp b/src/parse.cpp
index bf835ac55..1e88ef534 100644
--- a/src/parse.cpp
+++ b/src/parse.cpp
@@ -138,6 +138,7 @@ static const char* commands[] =
"projects",
"start",
"stats",
+ "stop",
"summary",
"tags",
"undelete",
diff --git a/src/task.cpp b/src/task.cpp
index 88711d8cf..1a54418f9 100644
--- a/src/task.cpp
+++ b/src/task.cpp
@@ -125,7 +125,11 @@ static void shortUsage (Config& conf)
row = table.addRow ();
table.addCell (row, 1, "task start ID");
- table.addCell (row, 2, "Marks specified task as started, starts the clock ticking");
+ table.addCell (row, 2, "Marks specified task as started");
+
+ row = table.addRow ();
+ table.addCell (row, 1, "task stop ID");
+ table.addCell (row, 2, "Removes the 'start' time from a task");
row = table.addRow ();
table.addCell (row, 1, "task done ID");
@@ -300,10 +304,6 @@ int main (int argc, char** argv)
std::string dataLocation = expandPath (conf.get ("data.location"));
tdb.dataDirectory (dataLocation);
- // Log commands, if desired.
- if (conf.get ("command.logging") == "on")
- tdb.logCommand (argc, argv);
-
// Set up TDB callback.
std::string shadowFile = expandPath (conf.get ("shadow.file"));
if (shadowFile != "")
@@ -766,6 +766,7 @@ void runTaskCommand (
else if (command == "completed") handleCompleted (tdb, task, conf);
else if (command == "delete") handleDelete (tdb, task, conf);
else if (command == "start") handleStart (tdb, task, conf);
+ else if (command == "stop") handleStop (tdb, task, conf);
else if (command == "done") handleDone (tdb, task, conf);
else if (command == "undo") handleUndo (tdb, task, conf);
else if (command == "export") handleExport (tdb, task, conf);
@@ -780,7 +781,6 @@ void runTaskCommand (
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 == "usage") handleReportUsage (tdb, task, conf);
else if (command == "" && task.getId ()) handleModify (tdb, task, conf);
else if (command == "help") longUsage (conf);
else shortUsage (conf);
diff --git a/src/task.h b/src/task.h
index bc15fbfc3..1f550bd34 100644
--- a/src/task.h
+++ b/src/task.h
@@ -79,6 +79,7 @@ void handleVersion (Config&);
void handleExport (TDB&, T&, Config&);
void handleDelete (TDB&, T&, Config&);
void handleStart (TDB&, T&, Config&);
+void handleStop (TDB&, T&, Config&);
void handleDone (TDB&, T&, Config&);
void handleUndo (TDB&, T&, Config&);
void handleModify (TDB&, T&, Config&);
From d6b30466c13eb45b73f70b13f6178f9b751fc44f Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sat, 1 Nov 2008 15:44:25 -0400
Subject: [PATCH 002/103] - "task ghistory" now displays a differently aligned
graph, allowing easier comparison by month of tasks added versus completed
and deleted.
---
ChangeLog | 2 ++
html/task.html | 2 ++
src/report.cpp | 34 +++++++++++++++++++++++-----------
3 files changed, 27 insertions(+), 11 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 52f729398..396fd1785 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -6,6 +6,8 @@
+ Removed "usage" command, and support for "command.logging" configuration
variable.
+ "task stop" can now remove the start time from a started task.
+ + "task ghistory" now displays a differently aligned graph, allowing
+ easier comparison by month of tasks added versus completed and deleted.
------ old releases ------------------------------
diff --git a/html/task.html b/html/task.html
index 57083e0a7..ccbbd3274 100644
--- a/html/task.html
+++ b/html/task.html
@@ -96,6 +96,8 @@
Removed "usage" command, and support for "command.logging" configuration
variable.
"task stop" can remove the start time from a started task.
+
"task ghistory" now displays a differently aligned graph, allowing
+ easier comparison by month of tasks added versus completed and deleted.
diff --git a/src/report.cpp b/src/report.cpp
index 2e60e498e..eb3a03de0 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -1380,7 +1380,7 @@ void handleReportGHistory (TDB& tdb, T& task, Config& conf)
endwin ();
}
#endif
- int widthOfBar = width - 15; // strlen ("2008 September ")
+ int widthOfBar = width - 15; // 15 == strlen ("2008 September ")
std::map groups;
std::map addedGroup;
@@ -1480,18 +1480,24 @@ void handleReportGHistory (TDB& tdb, T& task, Config& conf)
else
table.setTableDashedUnderline ();
- // Determine the longest line.
- int maxLine = 0;
+ // Determine the longest line, and the longest "added" line.
+ int maxAddedLine = 0;
+ int maxRemovedLine = 0;
foreach (i, groups)
{
- int line = addedGroup[i->first] + completedGroup[i->first] + deletedGroup[i->first];
+ if (completedGroup[i->first] + deletedGroup[i->first] > maxRemovedLine)
+ maxRemovedLine = completedGroup[i->first] + deletedGroup[i->first];
- if (line > maxLine)
- maxLine = line;
+ if (addedGroup[i->first] > maxAddedLine)
+ maxAddedLine = addedGroup[i->first];
}
+ int maxLine = maxAddedLine + maxRemovedLine;
+
if (maxLine > 0)
{
+ unsigned int leftOffset = (widthOfBar * maxAddedLine) / maxLine;
+
int totalAdded = 0;
int totalCompleted = 0;
int totalDeleted = 0;
@@ -1521,7 +1527,7 @@ void handleReportGHistory (TDB& tdb, T& task, Config& conf)
unsigned int completedBar = (widthOfBar * completedGroup[i->first]) / maxLine;
unsigned int deletedBar = (widthOfBar * deletedGroup[i->first]) / maxLine;
- std::string bar;
+ std::string bar = "";
if (conf.get ("color", true))
{
char number[24];
@@ -1552,9 +1558,12 @@ void handleReportGHistory (TDB& tdb, T& task, Config& conf)
dBar = " " + dBar;
}
- bar = Text::colorize (Text::black, Text::on_red, aBar);
- bar += Text::colorize (Text::black, Text::on_green, cBar);
- bar += Text::colorize (Text::black, Text::on_yellow, dBar);
+ while (bar.length () < leftOffset - aBar.length ())
+ bar += " ";
+
+ bar += Text::colorize (Text::black, Text::on_red, aBar);
+ bar += Text::colorize (Text::black, Text::on_green, cBar);
+ bar += Text::colorize (Text::black, Text::on_yellow, dBar);
}
else
{
@@ -1562,7 +1571,10 @@ void handleReportGHistory (TDB& tdb, T& task, Config& conf)
std::string cBar = ""; while (cBar.length () < completedBar) cBar += "X";
std::string dBar = ""; while (dBar.length () < deletedBar) dBar += "-";
- bar = aBar + cBar + dBar;
+ while (bar.length () < leftOffset - aBar.length ())
+ bar += " ";
+
+ bar += aBar + cBar + dBar;
}
table.addCell (row, 2, bar);
From 5f85550664f094f847af43bc19da755560e30ef4 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sat, 8 Nov 2008 22:43:40 -0500
Subject: [PATCH 003/103] - Removed support for the "showage" configuration
variable.
---
ChangeLog | 1 +
html/config.html | 6 ---
html/troubleshooting.html | 26 -------------
src/Config.cpp | 1 -
src/report.cpp | 82 ++++++++++++++++++---------------------
5 files changed, 38 insertions(+), 78 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 13dae5fc0..e765818e0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,6 +5,7 @@
+ Removed deprecated TUTORIAL file.
+ Removed "usage" command, and support for "command.logging" configuration
variable.
+ + Removed "showage" configuration variable.
+ "task stop" can now remove the start time from a started task.
+ "task ghistory" now displays a differently aligned graph, allowing
easier comparison by month of tasks added versus completed and deleted.
diff --git a/html/config.html b/html/config.html
index bbdb16b73..30db4d940 100644
--- a/html/config.html
+++ b/html/config.html
@@ -171,12 +171,6 @@
-
showage
-
- May be "yes" or "no". Determines whether the "Age"
- column appears on the "list" and "next" reports.
-
-
monthsperline
Determines how many months the "task calendar" command
diff --git a/html/troubleshooting.html b/html/troubleshooting.html
index 5e3147631..1876c7c66 100644
--- a/html/troubleshooting.html
+++ b/html/troubleshooting.html
@@ -60,32 +60,6 @@
-
-
How to get rid of the "Age" column
-
-
- The "Age" column that shows up on several reports is proving
- to be unpopular. In task 1.2.0 and later, here is how to
- remove it from the reports - make sure you have the line:
-
-
-
showage=no
-
-
- in your ~/.taskrc file.
-
- Note that the "task long" report does not obey this setting
- in versions prior to 1.3.1.
-
-
-
- The "showage" setting is supported in task 1.2.0 or later.
-
- The "task long" report supports this setting in versions 1.3.1
- or later.
-
Removed support for the "showage" configuration variable.
"task stop" can remove the start time from a started task.
"task ghistory" now displays a differently aligned graph, allowing
easier comparison by month of tasks added versus completed and deleted.
From ecdfb31553fb143d710092074ff09835963188b3 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sat, 8 Nov 2008 23:32:29 -0500
Subject: [PATCH 005/103] - "task version" command now reports unrecognized
configuration variables, which may be spelling mistakes or deprecated
variables.
---
ChangeLog | 2 ++
html/config.html | 10 ++++++++++
html/task.html | 2 ++
src/command.cpp | 36 ++++++++++++++++++++++++++++++++++++
4 files changed, 50 insertions(+)
diff --git a/ChangeLog b/ChangeLog
index 7d05412eb..fdd4d643e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -7,6 +7,8 @@
+ "task stop" can now remove the start time from a started task.
+ "task ghistory" now displays a differently aligned graph, allowing
easier comparison by month of tasks added versus completed and deleted.
+ + "task version" command now reports unrecognized configuration variables,
+ which may be spelling mistakes or deprecated variables.
------ old releases ------------------------------
diff --git a/html/config.html b/html/config.html
index 30db4d940..09add7bef 100644
--- a/html/config.html
+++ b/html/config.html
@@ -316,6 +316,16 @@ ID Project Pri Description
whenever the shadow file is updated by some task command.
+
+ Note that the command:
+
+
+
task version
+
+
+ will display the configuration variables found in the .taskrc file,
+ and will warn you of any variables that are not recognized.
+
- Copyright 2006-2008, P. Beckingham. All rights reserved.
+ Copyright 2006-2009, P. Beckingham. All rights reserved.
diff --git a/html/recur.html b/html/recur.html
index 978c94cef..fd81b6aca 100644
--- a/html/recur.html
+++ b/html/recur.html
@@ -155,7 +155,7 @@ recurrences of this same task? (y/n) y
- Copyright 2006-2008, P. Beckingham. All rights reserved.
+ Copyright 2006-2009, P. Beckingham. All rights reserved.
- Copyright 2006-2008, P. Beckingham. All rights reserved.
+ Copyright 2006-2009, P. Beckingham. All rights reserved.
diff --git a/html/simple.html b/html/simple.html
index 9e7f0f88c..860421d6a 100644
--- a/html/simple.html
+++ b/html/simple.html
@@ -305,7 +305,7 @@ ID Project Pri Due Active Age Description
- Copyright 2006-2008, P. Beckingham. All rights reserved.
+ Copyright 2006-2009, P. Beckingham. All rights reserved.
- Copyright 2006-2008, P. Beckingham. All rights reserved.
+ Copyright 2006-2009, P. Beckingham. All rights reserved.
diff --git a/html/usage.html b/html/usage.html
index feadd5ddd..9970427c6 100644
--- a/html/usage.html
+++ b/html/usage.html
@@ -93,7 +93,7 @@ Many characters have special meaning to the shell, including:
- Copyright 2006-2008, P. Beckingham. All rights reserved.
+ Copyright 2006-2009, P. Beckingham. All rights reserved.
- Copyright 2006-2008, P. Beckingham. All rights reserved.
+ Copyright 2006-2009, P. Beckingham. All rights reserved.
diff --git a/src/Config.cpp b/src/Config.cpp
index deff2922d..e9f1201b2 100644
--- a/src/Config.cpp
+++ b/src/Config.cpp
@@ -1,7 +1,7 @@
///////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
-// Copyright 2006 - 2008, Paul Beckingham.
+// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
diff --git a/src/Config.h b/src/Config.h
index 4488ec468..0286ea950 100644
--- a/src/Config.h
+++ b/src/Config.h
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
-// Copyright 2006 - 2008, Paul Beckingham.
+// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
diff --git a/src/Date.cpp b/src/Date.cpp
index 67ac7e7c7..995011345 100644
--- a/src/Date.cpp
+++ b/src/Date.cpp
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
-// Copyright 2006 - 2008, Paul Beckingham.
+// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
diff --git a/src/Date.h b/src/Date.h
index ad3f659e0..e8538435d 100644
--- a/src/Date.h
+++ b/src/Date.h
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
-// Copyright 2006 - 2008, Paul Beckingham.
+// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
diff --git a/src/Grid.cpp b/src/Grid.cpp
index faaa4e90f..a391aa75b 100644
--- a/src/Grid.cpp
+++ b/src/Grid.cpp
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
-// Copyright 2006 - 2008, Paul Beckingham.
+// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
diff --git a/src/Grid.h b/src/Grid.h
index cf9ff8ecb..e1315e8c3 100644
--- a/src/Grid.h
+++ b/src/Grid.h
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
-// Copyright 2006 - 2008, Paul Beckingham.
+// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
diff --git a/src/T.cpp b/src/T.cpp
index e243c1db6..a21b31638 100644
--- a/src/T.cpp
+++ b/src/T.cpp
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
-// Copyright 2006 - 2008, Paul Beckingham.
+// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
diff --git a/src/T.h b/src/T.h
index e26d25b5f..fc126ae34 100644
--- a/src/T.h
+++ b/src/T.h
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
-// Copyright 2006 - 2008, Paul Beckingham.
+// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
diff --git a/src/TDB.cpp b/src/TDB.cpp
index ba7b4eb2b..bce2d6e4e 100644
--- a/src/TDB.cpp
+++ b/src/TDB.cpp
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
-// Copyright 2006 - 2008, Paul Beckingham.
+// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
diff --git a/src/TDB.h b/src/TDB.h
index d335e909b..e654acc05 100644
--- a/src/TDB.h
+++ b/src/TDB.h
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
-// Copyright 2006 - 2008, Paul Beckingham.
+// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
diff --git a/src/Table.cpp b/src/Table.cpp
index 6de729b4b..f62fb2eae 100644
--- a/src/Table.cpp
+++ b/src/Table.cpp
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
-// Copyright 2006 - 2008, Paul Beckingham.
+// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
diff --git a/src/Table.h b/src/Table.h
index 6a793af0c..e1d244e14 100644
--- a/src/Table.h
+++ b/src/Table.h
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
-// Copyright 2006 - 2008, Paul Beckingham.
+// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
diff --git a/src/color.cpp b/src/color.cpp
index 9de9b7942..6231dfe1f 100644
--- a/src/color.cpp
+++ b/src/color.cpp
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
-// Copyright 2006 - 2008, Paul Beckingham.
+// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
diff --git a/src/color.h b/src/color.h
index 7c48d8e6a..d90b47c8d 100644
--- a/src/color.h
+++ b/src/color.h
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
-// Copyright 2006 - 2008, Paul Beckingham.
+// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
diff --git a/src/command.cpp b/src/command.cpp
index fb97800d6..084125bfd 100644
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
-// Copyright 2006 - 2008, Paul Beckingham.
+// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
@@ -343,7 +343,7 @@ std::string handleVersion (Config& conf)
}
}
- out << "Copyright (C) 2006 - 2008, P. Beckingham."
+ out << "Copyright (C) 2006 - 2009, P. Beckingham."
<< std::endl
<< (conf.get ("color", true) ? Text::colorize (Text::bold, Text::nocolor, PACKAGE) : PACKAGE)
<< " "
diff --git a/src/parse.cpp b/src/parse.cpp
index a2daea1fa..99f2d9187 100644
--- a/src/parse.cpp
+++ b/src/parse.cpp
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
-// Copyright 2006 - 2008, Paul Beckingham.
+// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
diff --git a/src/report.cpp b/src/report.cpp
index 4d8de003f..7b5fdcc46 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
-// Copyright 2006 - 2008, Paul Beckingham.
+// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
diff --git a/src/rules.cpp b/src/rules.cpp
index 4d9ccabe2..20f79ac5e 100644
--- a/src/rules.cpp
+++ b/src/rules.cpp
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
-// Copyright 2006 - 2008, Paul Beckingham.
+// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
diff --git a/src/task.cpp b/src/task.cpp
index 53b8b098e..e222e2702 100644
--- a/src/task.cpp
+++ b/src/task.cpp
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
-// Copyright 2006 - 2008, Paul Beckingham.
+// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
diff --git a/src/task.h b/src/task.h
index c2f609d6d..d84d6210f 100644
--- a/src/task.h
+++ b/src/task.h
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
-// Copyright 2006 - 2008, Paul Beckingham.
+// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
diff --git a/src/tests/tdb.t.cpp b/src/tests/tdb.t.cpp
index 129a0cdbf..3676f6517 100644
--- a/src/tests/tdb.t.cpp
+++ b/src/tests/tdb.t.cpp
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
-// Copyright 2006 - 2008, Paul Beckingham.
+// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
diff --git a/src/text.cpp b/src/text.cpp
index 90fed8aa2..46ae3bbe4 100644
--- a/src/text.cpp
+++ b/src/text.cpp
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
-// Copyright 2006 - 2008, Paul Beckingham.
+// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
diff --git a/src/util.cpp b/src/util.cpp
index fc52bb7bf..fd73c3b39 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
-// Copyright 2006 - 2008, Paul Beckingham.
+// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
From 6faf1e44f53a4affc369d80462f68d97f3fec2de Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sat, 14 Feb 2009 20:04:34 -0500
Subject: [PATCH 020/103] Bug Fix - lower case priorities
- Changed a call to isupper to islower. This was preventing the
internal modification to upper case.
- Updated ChangeLog accordingly.
---
ChangeLog | 1 +
src/text.cpp | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/ChangeLog b/ChangeLog
index 109aaa601..535a46ca6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -11,6 +11,7 @@
which may be spelling mistakes or deprecated variables.
+ "configure --enable-debug" now supported to suppress compiler optimization
to allow debugging.
+ + Allow lower case priorities, and automatically upper case them.
------ old releases ------------------------------
diff --git a/src/text.cpp b/src/text.cpp
index 46ae3bbe4..b459e2856 100644
--- a/src/text.cpp
+++ b/src/text.cpp
@@ -296,7 +296,7 @@ std::string upperCase (const std::string& input)
{
std::string output = input;
for (int i = 0; i < (int) input.length (); ++i)
- if (::isupper (input[i]))
+ if (::islower (input[i]))
output[i] = ::toupper (input[i]);
return output;
From 01b3cb190ccd6e7ec362a8545564db648286f212 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sat, 14 Feb 2009 20:19:47 -0500
Subject: [PATCH 021/103] Configuration Variable - due
- Added support for the "due" configuration variable that defines
how many days into the future when a task is considered due.
---
ChangeLog | 2 ++
html/config.html | 8 ++++++++
html/task.html | 3 +++
src/Config.cpp | 1 +
src/report.cpp | 18 +++++++++---------
src/rules.cpp | 8 ++++++--
src/task.h | 2 +-
7 files changed, 30 insertions(+), 12 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 535a46ca6..be2fb45f4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -12,6 +12,8 @@
+ "configure --enable-debug" now supported to suppress compiler optimization
to allow debugging.
+ Allow lower case priorities, and automatically upper case them.
+ + Added support for "due" configuration variable which defines the number
+ of days in the future when a task is considered due.
------ old releases ------------------------------
diff --git a/html/config.html b/html/config.html
index 0b10b7224..fd4bc71a4 100644
--- a/html/config.html
+++ b/html/config.html
@@ -195,6 +195,14 @@
Defaults to 80.
+
due
+
+
+ This is the number of days into the future that define when a
+ task is considered due, and is colored accordingly.
+ Defaults to 7.
+
+
color
May be "on" or "off". Determines whether task uses color.
diff --git a/html/task.html b/html/task.html
index 5bae3744c..f222bf0fa 100644
--- a/html/task.html
+++ b/html/task.html
@@ -104,6 +104,9 @@
which may be spelling mistakes or deprecated variables.
"configure --enable-debug" now supported to suppress compiler optimization
to allow debugging.
+
Allow lower case priorities, and automatically upper case them.
+
Added support for "due" configuration variable which defines the number
+ of days in the future when a task is considered due.
diff --git a/src/Config.cpp b/src/Config.cpp
index e9f1201b2..7e1eeadd4 100644
--- a/src/Config.cpp
+++ b/src/Config.cpp
@@ -118,6 +118,7 @@ void Config::createDefault (const std::string& home)
fprintf (out, "monthsperline=1\n");
fprintf (out, "curses=on\n");
fprintf (out, "color=on\n");
+ fprintf (out, "due=7\n");
fprintf (out, "color.overdue=bold_red\n");
fprintf (out, "#color.due=on_bright_yellow\n");
diff --git a/src/report.cpp b/src/report.cpp
index 7b5fdcc46..ecc8081bd 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -258,7 +258,7 @@ std::string handleList (TDB& tdb, T& task, Config& conf)
{
Text::color fg = Text::colorCode (refTask.getAttribute ("fg"));
Text::color bg = Text::colorCode (refTask.getAttribute ("bg"));
- autoColorize (refTask, fg, bg);
+ autoColorize (refTask, fg, bg, conf);
table.setRowFg (row, fg);
table.setRowBg (row, bg);
@@ -390,7 +390,7 @@ std::string handleSmallList (TDB& tdb, T& task, Config& conf)
{
Text::color fg = Text::colorCode (refTask.getAttribute ("fg"));
Text::color bg = Text::colorCode (refTask.getAttribute ("bg"));
- autoColorize (refTask, fg, bg);
+ autoColorize (refTask, fg, bg, conf);
table.setRowFg (row, fg);
table.setRowBg (row, bg);
@@ -489,7 +489,7 @@ std::string handleCompleted (TDB& tdb, T& task, Config& conf)
{
Text::color fg = Text::colorCode (refTask.getAttribute ("fg"));
Text::color bg = Text::colorCode (refTask.getAttribute ("bg"));
- autoColorize (refTask, fg, bg);
+ autoColorize (refTask, fg, bg, conf);
table.setRowFg (row, fg);
table.setRowBg (row, bg);
}
@@ -851,7 +851,7 @@ std::string handleLongList (TDB& tdb, T& task, Config& conf)
{
Text::color fg = Text::colorCode (refTask.getAttribute ("fg"));
Text::color bg = Text::colorCode (refTask.getAttribute ("bg"));
- autoColorize (refTask, fg, bg);
+ autoColorize (refTask, fg, bg, conf);
table.setRowFg (row, fg);
table.setRowBg (row, bg);
@@ -1180,7 +1180,7 @@ std::string handleReportNext (TDB& tdb, T& task, Config& conf)
{
Text::color fg = Text::colorCode (refTask.getAttribute ("fg"));
Text::color bg = Text::colorCode (refTask.getAttribute ("bg"));
- autoColorize (refTask, fg, bg);
+ autoColorize (refTask, fg, bg, conf);
table.setRowFg (row, fg);
table.setRowBg (row, bg);
@@ -1962,7 +1962,7 @@ std::string handleReportActive (TDB& tdb, T& task, Config& conf)
{
Text::color fg = Text::colorCode (refTask.getAttribute ("fg"));
Text::color bg = Text::colorCode (refTask.getAttribute ("bg"));
- autoColorize (refTask, fg, bg);
+ autoColorize (refTask, fg, bg, conf);
table.setRowFg (row, fg);
table.setRowBg (row, bg);
@@ -2076,7 +2076,7 @@ std::string handleReportOverdue (TDB& tdb, T& task, Config& conf)
{
Text::color fg = Text::colorCode (refTask.getAttribute ("fg"));
Text::color bg = Text::colorCode (refTask.getAttribute ("bg"));
- autoColorize (refTask, fg, bg);
+ autoColorize (refTask, fg, bg, conf);
table.setRowFg (row, fg);
table.setRowBg (row, bg);
@@ -2220,7 +2220,7 @@ std::string handleReportOldest (TDB& tdb, T& task, Config& conf)
{
Text::color fg = Text::colorCode (refTask.getAttribute ("fg"));
Text::color bg = Text::colorCode (refTask.getAttribute ("bg"));
- autoColorize (refTask, fg, bg);
+ autoColorize (refTask, fg, bg, conf);
table.setRowFg (row, fg);
table.setRowBg (row, bg);
@@ -2368,7 +2368,7 @@ std::string handleReportNewest (TDB& tdb, T& task, Config& conf)
{
Text::color fg = Text::colorCode (refTask.getAttribute ("fg"));
Text::color bg = Text::colorCode (refTask.getAttribute ("bg"));
- autoColorize (refTask, fg, bg);
+ autoColorize (refTask, fg, bg, conf);
table.setRowFg (row, fg);
table.setRowBg (row, bg);
diff --git a/src/rules.cpp b/src/rules.cpp
index 20f79ac5e..f33354c9f 100644
--- a/src/rules.cpp
+++ b/src/rules.cpp
@@ -80,7 +80,11 @@ void initializeColorRules (Config& conf)
}
////////////////////////////////////////////////////////////////////////////////
-void autoColorize (T& task, Text::color& fg, Text::color& bg)
+void autoColorize (
+ T& task,
+ Text::color& fg,
+ Text::color& bg,
+ Config& conf)
{
// Note: fg, bg already contain colors specifically assigned via command.
// Note: These rules form a hierarchy - the last rule is king.
@@ -159,7 +163,7 @@ void autoColorize (T& task, Text::color& fg, Text::color& bg)
{
Date dueDate (::atoi (due.c_str ()));
Date now;
- Date then (now + 7 * 86400);
+ Date then (now + conf.get ("due", 7) * 86400);
// Overdue
if (dueDate < now)
diff --git a/src/task.h b/src/task.h
index d84d6210f..8c151cb83 100644
--- a/src/task.h
+++ b/src/task.h
@@ -141,6 +141,6 @@ std::string expandPath (const std::string&);
// rules.cpp
void initializeColorRules (Config&);
-void autoColorize (T&, Text::color&, Text::color&);
+void autoColorize (T&, Text::color&, Text::color&, Config&);
////////////////////////////////////////////////////////////////////////////////
From e65a45ce17e73c72e7a9793a1d89026cf4c1124c Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sat, 14 Feb 2009 23:13:31 -0500
Subject: [PATCH 022/103] Bug Fix
- Fixed bug in split functions, which was causing empty strings to be
split into a single element list consisting of one empty string.
The symptom was that all tasks without tags appeared to have one
zero-length tag and the task was colored according to color.tagged.
---
src/text.cpp | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/text.cpp b/src/text.cpp
index b459e2856..f18fec8e4 100644
--- a/src/text.cpp
+++ b/src/text.cpp
@@ -54,6 +54,7 @@ void split (
const std::string& input,
const char delimiter)
{
+ results.clear ();
std::string::size_type start = 0;
std::string::size_type i;
while ((i = input.find (delimiter, start)) != std::string::npos)
@@ -62,7 +63,8 @@ void split (
start = i + 1;
}
- results.push_back (input.substr (start, std::string::npos));
+ if (input.length ())
+ results.push_back (input.substr (start, std::string::npos));
}
////////////////////////////////////////////////////////////////////////////////
@@ -71,6 +73,7 @@ void split (
const std::string& input,
const std::string& delimiter)
{
+ results.clear ();
std::string::size_type length = delimiter.length ();
std::string::size_type start = 0;
@@ -81,7 +84,8 @@ void split (
start = i + length;
}
- results.push_back (input.substr (start, std::string::npos));
+ if (input.length ())
+ results.push_back (input.substr (start, std::string::npos));
}
////////////////////////////////////////////////////////////////////////////////
From 096a4b9bdb254bd987c00f9054800a6e37cda6ae Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sat, 14 Feb 2009 23:13:31 -0500
Subject: [PATCH 023/103] Bug Fix - split
- Fixed bug in split functions, which was causing empty strings to be
split into a single element list consisting of one empty string.
The symptom was that all tasks without tags appeared to have one
zero-length tag and the task was colored according to color.tagged.
---
src/text.cpp | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/text.cpp b/src/text.cpp
index b459e2856..f18fec8e4 100644
--- a/src/text.cpp
+++ b/src/text.cpp
@@ -54,6 +54,7 @@ void split (
const std::string& input,
const char delimiter)
{
+ results.clear ();
std::string::size_type start = 0;
std::string::size_type i;
while ((i = input.find (delimiter, start)) != std::string::npos)
@@ -62,7 +63,8 @@ void split (
start = i + 1;
}
- results.push_back (input.substr (start, std::string::npos));
+ if (input.length ())
+ results.push_back (input.substr (start, std::string::npos));
}
////////////////////////////////////////////////////////////////////////////////
@@ -71,6 +73,7 @@ void split (
const std::string& input,
const std::string& delimiter)
{
+ results.clear ();
std::string::size_type length = delimiter.length ();
std::string::size_type start = 0;
@@ -81,7 +84,8 @@ void split (
start = i + length;
}
- results.push_back (input.substr (start, std::string::npos));
+ if (input.length ())
+ results.push_back (input.substr (start, std::string::npos));
}
////////////////////////////////////////////////////////////////////////////////
From 6764a6a7ec18c62167a03ab5223c16f7ab508987 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sun, 15 Feb 2009 14:54:54 -0500
Subject: [PATCH 024/103] Custom Reports - basic implementation
- Custom reports can be defined and run.
- Custom columns included.
- Custom filter applied.
- Custom sorting applied.
---
src/report.cpp | 279 +++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 268 insertions(+), 11 deletions(-)
diff --git a/src/report.cpp b/src/report.cpp
index ecc8081bd..7a1fdc688 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -2673,6 +2673,8 @@ void gatherNextTasks (
}
////////////////////////////////////////////////////////////////////////////////
+// This report will eventually become the one report that many others morph into
+// via the .taskrc file.
std::string handleCustomReport (
TDB& tdb,
T& task,
@@ -2699,30 +2701,285 @@ std::string handleCustomReport (
std::vector sortOrder;
split (sortOrder, sortList, ',');
- std::string filter = conf.get ("report." + report + ".filter");
+ std::string filterList = conf.get ("report." + report + ".filter");
std::cout << "# columns " << columnList << std::endl
<< "# sort " << sortList << std::endl
- << "# filter " << filter << std::endl;
+ << "# filter " << filterList << std::endl;
- // TODO Load pending tasks.
+ // Load all pending tasks.
std::vector tasks;
- tdb.allT (tasks);
-// filter (tasks, task);
+ tdb.allPendingT (tasks);
- // TODO Apply filters.
+ // Apply filters.
+ {
+ std::vector args;
+ split (args, filterList, ' ');
+
+ std::string ignore;
+ T filterTask;
+ parse (args, ignore, filterTask, conf);
+
+ filter (tasks, filterTask);
+ }
+
+ // Initialize colorization for subsequent auto colorization.
+ initializeColorRules (conf);
Table table;
table.setTableWidth (width);
+ table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
+ for (unsigned int i = 0; i < tasks.size (); ++i)
+ table.addRow ();
+
+ int columnCount = 0;
+ int dueColumn = -1;
foreach (col, columns)
{
- // TODO Add column.
- // TODO Add underline.
-
- // TODO Add data.
- foreach (t, tasks)
+ // Add each column individually.
+ if (*col == "id")
{
+ table.addColumn ("ID");
+ table.setColumnWidth (columnCount, Table::minimum);
+ table.setColumnJustification (columnCount, Table::right);
+
+ for (unsigned int row = 0; row < tasks.size(); ++row)
+ table.addCell (row, columnCount, tasks[row].getId ());
+ }
+
+ else if (*col == "uuid")
+ {
+ table.addColumn ("UUID");
+ table.setColumnWidth (columnCount, Table::minimum);
+ table.setColumnJustification (columnCount, Table::left);
+
+ for (unsigned int row = 0; row < tasks.size(); ++row)
+ table.addCell (row, columnCount, tasks[row].getUUID ());
+ }
+
+ else if (*col == "project")
+ {
+ table.addColumn ("Project");
+ table.setColumnWidth (columnCount, Table::minimum);
+ table.setColumnJustification (columnCount, Table::left);
+
+ for (unsigned int row = 0; row < tasks.size(); ++row)
+ table.addCell (row, columnCount, tasks[row].getAttribute ("project"));
+ }
+
+ else if (*col == "priority")
+ {
+ table.addColumn ("Pri");
+ table.setColumnWidth (columnCount, Table::minimum);
+ table.setColumnJustification (columnCount, Table::left);
+
+ for (unsigned int row = 0; row < tasks.size(); ++row)
+ table.addCell (row, columnCount, tasks[row].getAttribute ("priority"));
+ }
+
+ else if (*col == "entry")
+ {
+ table.addColumn ("Added");
+ table.setColumnWidth (columnCount, Table::minimum);
+ table.setColumnJustification (columnCount, Table::right);
+
+ std::string entered;
+ for (unsigned int row = 0; row < tasks.size(); ++row)
+ {
+ entered = tasks[row].getAttribute ("entry");
+ if (entered.length ())
+ {
+ Date dt (::atoi (entered.c_str ()));
+ entered = dt.toString (conf.get ("dateformat", "m/d/Y"));
+ table.addCell (row, columnCount, entered);
+ }
+ }
+ }
+
+ else if (*col == "start")
+ {
+ table.addColumn ("Started");
+ table.setColumnWidth (columnCount, Table::minimum);
+ table.setColumnJustification (columnCount, Table::right);
+
+ std::string started;
+ for (unsigned int row = 0; row < tasks.size(); ++row)
+ {
+ started = tasks[row].getAttribute ("start");
+ if (started.length ())
+ {
+ Date dt (::atoi (started.c_str ()));
+ started = dt.toString (conf.get ("dateformat", "m/d/Y"));
+ table.addCell (row, columnCount, started);
+ }
+ }
+ }
+
+ else if (*col == "due")
+ {
+ table.addColumn ("Due");
+ table.setColumnWidth (columnCount, Table::minimum);
+ table.setColumnJustification (columnCount, Table::right);
+
+ std::string due;
+ for (unsigned int row = 0; row < tasks.size(); ++row)
+ {
+ due = tasks[row].getAttribute ("due");
+ if (due.length ())
+ {
+ Date dt (::atoi (due.c_str ()));
+ due = dt.toString (conf.get ("dateformat", "m/d/Y"));
+ table.addCell (row, columnCount, due);
+ }
+ }
+
+ dueColumn = columnCount;
+ }
+
+ else if (*col == "age")
+ {
+ table.addColumn ("Age");
+ table.setColumnWidth (columnCount, Table::minimum);
+ table.setColumnJustification (columnCount, Table::right);
+
+ std::string created;
+ std::string age;
+ Date now;
+ for (unsigned int row = 0; row < tasks.size(); ++row)
+ {
+ created = tasks[row].getAttribute ("entry");
+ if (created.length ())
+ {
+ Date dt (::atoi (created.c_str ()));
+ formatTimeDeltaDays (age, (time_t) (now - dt));
+ table.addCell (row, columnCount, age);
+ }
+ }
+ }
+
+ else if (*col == "active")
+ {
+ table.addColumn ("Active");
+ table.setColumnWidth (columnCount, Table::minimum);
+ table.setColumnJustification (columnCount, Table::left);
+
+ for (unsigned int row = 0; row < tasks.size(); ++row)
+ if (tasks[row].getAttribute ("start") != "")
+ table.addCell (row, columnCount, "*");
+ }
+
+ else if (*col == "tags")
+ {
+ table.addColumn ("Tags");
+ table.setColumnWidth (columnCount, Table::minimum);
+ table.setColumnJustification (columnCount, Table::left);
+
+ std::vector all;
+ std::string tags;
+ for (unsigned int row = 0; row < tasks.size(); ++row)
+ {
+ tasks[row].getTags (all);
+ join (tags, " ", all);
+ table.addCell (row, columnCount, tags);
+ }
+ }
+
+ else if (*col == "description")
+ {
+ table.addColumn ("Description");
+ table.setColumnWidth (columnCount, Table::flexible);
+ table.setColumnJustification (columnCount, Table::left);
+
+ for (unsigned int row = 0; row < tasks.size(); ++row)
+ table.addCell (row, columnCount, tasks[row].getDescription ());
+ }
+
+ // Common to all columns.
+ // Add underline.
+ if (conf.get (std::string ("color"), true))
+ table.setColumnUnderline (columnCount);
+ else
+ table.setTableDashedUnderline ();
+
+ ++columnCount;
+ }
+
+ // Dynamically add sort criteria.
+ // Build a map of column names -> index.
+ std::map columnIndex;
+ for (unsigned int c = 0; c < columns.size (); ++c)
+ columnIndex[columns[c]] = c;
+
+ foreach (sortColumn, sortOrder)
+ {
+ // Separate column and direction.
+ std::string column = sortColumn->substr (0, sortColumn->length () - 1);
+ char direction = (*sortColumn)[sortColumn->length () - 1];
+
+ if (column == "id")
+ table.sortOn (columnIndex[column],
+ (direction == '+' ?
+ Table::ascendingNumeric :
+ Table::descendingNumeric));
+
+ else if (column == "priority")
+ table.sortOn (columnIndex[column],
+ (direction == '+' ?
+ Table::ascendingPriority :
+ Table::descendingPriority));
+
+ else if (column == "entry" || column == "start" || column == "due")
+ table.sortOn (columnIndex[column],
+ (direction == '+' ?
+ Table::ascendingDate :
+ Table::descendingDate));
+
+ else
+ table.sortOn (columnIndex[column],
+ (direction == '+' ?
+ Table::ascendingCharacter :
+ Table::descendingCharacter));
+ }
+
+ // Now auto colorize all rows.
+ std::string due;
+ bool imminent;
+ bool overdue;
+ for (unsigned int row = 0; row < tasks.size (); ++row)
+ {
+ imminent = false;
+ overdue = false;
+ due = tasks[row].getAttribute ("due");
+ if (due.length ())
+ {
+ switch (getDueState (due))
+ {
+ case 2: overdue = true; break;
+ case 1: imminent = true; break;
+ case 0:
+ default: break;
+ }
+ }
+
+ if (conf.get ("color", true))
+ {
+ Text::color fg = Text::colorCode (tasks[row].getAttribute ("fg"));
+ Text::color bg = Text::colorCode (tasks[row].getAttribute ("bg"));
+ autoColorize (tasks[row], fg, bg, conf);
+ table.setRowFg (row, fg);
+ table.setRowBg (row, bg);
+
+ if (fg == Text::nocolor)
+ {
+ if (dueColumn != -1)
+ {
+ if (overdue)
+ table.setCellFg (row, columnCount, Text::colorCode (conf.get ("color.overdue", "red")));
+ else if (imminent)
+ table.setCellFg (row, columnCount, Text::colorCode (conf.get ("color.due", "yellow")));
+ }
+ }
}
}
From 481a0aa1ebf1133803820eed5ac6c0d1f1546105 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sun, 15 Feb 2009 15:13:24 -0500
Subject: [PATCH 025/103] Custom Reports - old reports removed
---
src/report.cpp | 464 +------------------------------------------------
src/task.cpp | 3 -
src/task.h | 3 -
3 files changed, 5 insertions(+), 465 deletions(-)
diff --git a/src/report.cpp b/src/report.cpp
index 7a1fdc688..740a88712 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -139,285 +139,6 @@ void filter (std::vector& all, T& task)
all = filtered;
}
-////////////////////////////////////////////////////////////////////////////////
-// Successively apply filters based on the task object built from the command
-// line. Tasks that match all the specified criteria are listed.
-std::string handleList (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 tasks;
- tdb.allPendingT (tasks);
- handleRecurrence (tdb, tasks);
- filter (tasks, task);
-
- initializeColorRules (conf);
-
- // 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 (std::string ("color"), true))
- {
- 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 < tasks.size (); ++i)
- {
- T refTask (tasks[i]);
- if (refTask.getStatus () != T::pending)
- continue;
-
- // 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 now;
- 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))
- {
- 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. Show a narrow
-// list that works better on mobile devices.
-std::string handleSmallList (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 tasks;
- tdb.allPendingT (tasks);
- handleRecurrence (tdb, tasks);
- filter (tasks, task);
-
- initializeColorRules (conf);
-
- // Create a table for output.
- Table table;
- table.setTableWidth (width);
- table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
- table.addColumn ("ID");
- table.addColumn ("Project");
- table.addColumn ("Pri");
- table.addColumn ("Description");
-
- if (conf.get ("color", true))
- {
- table.setColumnUnderline (0);
- table.setColumnUnderline (1);
- table.setColumnUnderline (2);
- table.setColumnUnderline (3);
- }
- else
- table.setTableDashedUnderline ();
-
- table.setColumnWidth (0, Table::minimum);
- table.setColumnWidth (1, Table::minimum);
- table.setColumnWidth (2, Table::minimum);
- table.setColumnWidth (3, Table::flexible);
-
- table.setColumnJustification (0, Table::right);
- table.setColumnJustification (3, Table::left);
-
- table.sortOn (2, Table::descendingPriority);
- table.sortOn (1, Table::ascendingCharacter);
-
- // Iterate over each task, and apply selection criteria.
- for (unsigned int i = 0; i < tasks.size (); ++i)
- {
- T refTask (tasks[i]);
-
- // 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 now;
- 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, 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, 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.
@@ -707,177 +428,6 @@ std::string handleInfo (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 handleLongList (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 all the tasks.
- std::vector tasks;
- tdb.allPendingT (tasks);
- handleRecurrence (tdb, tasks);
- filter (tasks, task);
-
- initializeColorRules (conf);
-
- // Create a table for output.
- Table table;
- table.setTableWidth (width);
- table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
- table.addColumn ("ID");
- table.addColumn ("Project");
- table.addColumn ("Pri");
- table.addColumn ("Entry");
- table.addColumn ("Start");
- table.addColumn ("Due");
- table.addColumn ("Age");
- table.addColumn ("Tags");
- table.addColumn ("Description");
-
- if (conf.get ("color", true))
- {
- table.setColumnUnderline (0);
- table.setColumnUnderline (1);
- table.setColumnUnderline (2);
- table.setColumnUnderline (3);
- table.setColumnUnderline (4);
- table.setColumnUnderline (5);
- table.setColumnUnderline (6);
- table.setColumnUnderline (7);
- table.setColumnUnderline (8);
- }
- 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::minimum);
- table.setColumnWidth (7, Table::minimum);
- table.setColumnWidth (8, Table::flexible);
-
- table.setColumnJustification (0, Table::right);
- table.setColumnJustification (3, Table::right);
- table.setColumnJustification (4, Table::right);
- table.setColumnJustification (5, Table::right);
- table.setColumnJustification (6, Table::right);
-
- table.sortOn (5, Table::ascendingDate);
- table.sortOn (2, Table::descendingPriority);
- table.sortOn (1, Table::ascendingCharacter);
-
- // Iterate over each task, and apply selection criteria.
- for (unsigned int i = 0; i < tasks.size (); ++i)
- {
- T refTask (tasks[i]);
-
- Date now;
-
- std::string started = refTask.getAttribute ("start");
- if (started.length ())
- {
- Date dt (::atoi (started.c_str ()));
- started = dt.toString (conf.get ("dateformat", "m/d/Y"));
- }
-
- std::string entered = refTask.getAttribute ("entry");
- if (entered.length ())
- {
- Date dt (::atoi (entered.c_str ()));
- entered = dt.toString (conf.get ("dateformat", "m/d/Y"));
- }
-
- // 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 age;
- std::string created = refTask.getAttribute ("entry");
- if (created.length ())
- {
- Date dt (::atoi (created.c_str ()));
- formatTimeDeltaDays (age, (time_t) (now - dt));
- }
-
- // Make a list of tags.
- std::string tags;
- std::vector all;
- refTask.getTags (all);
- join (tags, " ", all);
-
- // 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, entered);
- table.addCell (row, 4, started);
- table.addCell (row, 5, due);
- table.addCell (row, 6, age);
- table.addCell (row, 7, tags);
- table.addCell (row, 8, 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, 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 ();
-}
-
////////////////////////////////////////////////////////////////////////////////
// Project Tasks Avg Age Status
// A 12 13d XXXXXXXX------
@@ -2702,10 +2252,8 @@ std::string handleCustomReport (
split (sortOrder, sortList, ',');
std::string filterList = conf.get ("report." + report + ".filter");
-
- std::cout << "# columns " << columnList << std::endl
- << "# sort " << sortList << std::endl
- << "# filter " << filterList << std::endl;
+ std::vector filterArgs;
+ split (filterArgs, filterList, ' ');
// Load all pending tasks.
std::vector tasks;
@@ -2713,14 +2261,12 @@ std::string handleCustomReport (
// Apply filters.
{
- std::vector args;
- split (args, filterList, ' ');
-
std::string ignore;
T filterTask;
- parse (args, ignore, filterTask, conf);
+ parse (filterArgs, ignore, filterTask, conf);
- filter (tasks, filterTask);
+ filter (tasks, filterTask); // Filter from custom report
+ filter (tasks, task); // Filter from command line
}
// Initialize colorization for subsequent auto colorization.
diff --git a/src/task.cpp b/src/task.cpp
index e222e2702..84a74b24c 100644
--- a/src/task.cpp
+++ b/src/task.cpp
@@ -784,9 +784,6 @@ std::string runTaskCommand (
else if (command == "stop") { out = handleStop (tdb, task, conf ); }
else if (command == "undo") { out = handleUndo (tdb, task, conf ); }
else if (command == "stats") { out = handleReportStats (tdb, task, conf ); }
- else if (command == "list") { if (gc) tdb.gc (); out = handleList (tdb, task, conf ); } // TODO replace with Custom
- else if (command == "long") { if (gc) tdb.gc (); out = handleLongList (tdb, task, conf ); } // TODO replace with Custom
- else if (command == "ls") { if (gc) tdb.gc (); out = handleSmallList (tdb, task, conf ); } // TODO replace with Custom
else if (command == "completed") { if (gc) tdb.gc (); out = handleCompleted (tdb, task, conf ); } // TODO replace with Custom
else if (command == "summary") { if (gc) tdb.gc (); out = handleReportSummary (tdb, task, conf ); }
else if (command == "next") { if (gc) tdb.gc (); out = handleReportNext (tdb, task, conf ); } // TODO replace with Custom
diff --git a/src/task.h b/src/task.h
index 8c151cb83..57b19f652 100644
--- a/src/task.h
+++ b/src/task.h
@@ -89,10 +89,7 @@ std::string handleColor (Config&);
// report.cpp
void filter (std::vector&, T&);
-std::string handleList (TDB&, T&, Config&);
std::string handleInfo (TDB&, T&, Config&);
-std::string handleLongList (TDB&, T&, Config&);
-std::string handleSmallList (TDB&, T&, Config&);
std::string handleCompleted (TDB&, T&, Config&);
std::string handleReportSummary (TDB&, T&, Config&);
std::string handleReportNext (TDB&, T&, Config&);
From 4e63d93005757e2009ce63fac2dcc66db8243545 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sun, 15 Feb 2009 16:54:59 -0500
Subject: [PATCH 026/103] Documentation Update
- Added commit ids to ChangeLog
- Added tags to respective commit ids
---
ChangeLog | 30 +++++++++++++++++-------------
html/task.html | 4 ++++
2 files changed, 21 insertions(+), 13 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index be2fb45f4..41018682f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -14,10 +14,14 @@
+ Allow lower case priorities, and automatically upper case them.
+ Added support for "due" configuration variable which defines the number
of days in the future when a task is considered due.
+ + 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.
------ old releases ------------------------------
-1.4.3 (11/1/2008)
+1.4.3 (11/1/2008) 8639e9260646c8c9224e0fc47e5d2443b46eecfc
+ Fixed misleading task count at bottom on "info" report.
+ Added support for a shadow file that contains a plain text task report,
with the "shadow.file" and "shadow.command" configuration variables
@@ -31,7 +35,7 @@
+ Added documentation for Shadow files.
+ Added documentation for task filters.
-1.4.2 (9/18/2008)
+1.4.2 (9/18/2008) e7304e86ce9bb80978c7055fd2a9e999619a6fb8
+ "task undo" can now retract a "task done" command, provided no reports
have been run (and therefore TDB::gc run)
+ Task now correctly sorts on entire strings, instead of just the first
@@ -54,13 +58,13 @@
+ Bug: Source now properly includes in order to build clean
using gcc 4.3 (thanks to H. İbrahim Güngör)
-1.4.1 (7/18/2008)
+1.4.1 (7/18/2008) e080c3168c6064628ab85b21bd859d9875a3a9a7
+ Bug: Descriptions can not be altered with "task 123 New description"
+ Tweak: For "task calendar" month names are now centered over the month
+ Removed TUTORIAL file contents in favor of online version
+ Provided Mac .pkg binary
-1.4.0 (7/10/2008)
+1.4.0 (7/10/2008) 60b7d15a1d22e064acf0974c5d7eabbb57dd8071
+ New recurring tasks feature
+ "task undelete" can now undelete erroneously deleted tasks, provided no
reports have been run (and therefore TDB::gc run)
@@ -78,7 +82,7 @@
+ Bug: Adding a blank priority resulted in an assigned garbage value
+ Bug: Fixed parsing of date "07/08/2008" when using dateformat "m/d/Y"
-1.3.1 (6/21/2008)
+1.3.1 (6/21/2008) 3a6de7d9402f2609a773a73b16eff97b14a32869
+ New configuration variable, "defaultwidth" that determines the width
of tables when ncurses support is not available
+ Bug: "showage" configuration variable should apply to all reports, not
@@ -89,7 +93,7 @@
+ Bug: Task now will recreate a missing ~/.taskrc file, OR a missing
~/.task directory
-1.3.0 (6/18/2008)
+1.3.0 (6/18/2008) 6673e408a223af98c38779c20b08524042c0edfa
+ "task calendar" now displays multiple months per line, adjustable by the
"monthsperline" configuration variable. Feature added by Damian Glenny
+ "task export" can now filter tasks like the reports
@@ -104,7 +108,7 @@
days gets added to the entry date of task 2..n
+ Bug: Fixed bug whereby "1 wks" was being improperly pluralized
-1.2.0 (6/13/2008)
+1.2.0 (6/13/2008) c393d47cdfe7e197a31e94f4bb764474fa05ad8d
+ Bug: "dateformat" configuration variable used to display dates, but
not parse them
+ "task list x" now performs a caseless comparison between "x" and the
@@ -114,7 +118,7 @@
"list" and "next" reports
+ Improved TUTORIAL
-1.1.0 (6/7/2008)
+1.1.0 (6/7/2008) 73286e86628725b346db2a25fbcd4bd68efb9b3a
+ "blanklines" configuration to stop displaying unnecessary white
space and thus work better on small-screen devices
+ "dateformat" configuration now determines how dates are formatted
@@ -122,11 +126,11 @@
+ http://www.beckingham.net/task.html home page set up
+ Added tags to the "task long" report
-1.0.1 (6/4/2008)
+1.0.1 (6/4/2008) d216d401217027d93581808fc8944ab7d6b85fb0
+ Bug: UUID generator not properly terminating string.
+ Bug: srandom/srand not called prior to UUID generation.
-1.0.0 (6/3/2008)
+1.0.0 (6/3/2008) f3de5c07118c597091a05c7d7fe8bdeae95474c1
+ New movie made, uploaded
+ Bug: assertion fails on mobile for t v
+ Bug: configure.ac does not properly determine ncurses availability
@@ -139,19 +143,19 @@
+ Added rules for colorization by tag, project and keyword
+ Added legend to "task calendar"
-0.9.9 (5/27/2008)
+0.9.9 (5/27/2008) 2ecf50032226c91b406f247417a063dc17c8e324
+ Autoconf/automake behaving properly.
+ Clean build on OS X 10.5.
+ Clean build on Ubuntu 8.0.
+ Clean build on Fedora Core 8.
+ Clean build on Fedora Core 9.
-0.9.8 (5/25/2008)
+0.9.8 (5/25/2008) 18fd59a1edb20e5c68d086a97fae5fa9f6bb348a
+ Added "task color" command.
+ Removed unnecessary files.
+ Completed documentation.
-0.9.7 (5/24/2008)
+0.9.7 (5/24/2008) 25dc4150947a3e612c8118838d04b3bbe68441f7
+ Migrated old compiler flags into Makefile.am
+ Added ncurses endwin function check to configure.ac
+ Set up structure for AUTHORS file.
diff --git a/html/task.html b/html/task.html
index f222bf0fa..7e6e77a03 100644
--- a/html/task.html
+++ b/html/task.html
@@ -107,6 +107,10 @@
Allow lower case priorities, and automatically upper case them.
Added support for "due" configuration variable which defines the number
of days in the future when a task is considered due.
+
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.
+ 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.
+
+
+
+ More importantly, you can define your own. Here are the
+ two necessary items in the .taskrc file that define a new
+ report:
+
+ This defines a report, called "mine", that has four columns:
+ id, project, priority and description. It will be sorted on
+ two columns: by descending priority then ascending project.
+ Because this report is called "mine", it can be run with the
+ command:
+
+
+
% task mine
+
+
+ A filter can also be specified like this:
+
+
+
report.mine.filter=priority:H +bug
+
+
+ This adds a filter so that only tasks with priority "H" and
+ with the "bug" tag are included in the report. This filter
+ definition is optional.
+
+
+
+ Here is a list of all the possible columns that may be included
+ in a report:
+
+
+
+
id
+
uuid
+
project
+
priority
+
entry
+
start
+
due
+
age
+
active
+
tags
+
description
+
+
+
+ Custom reports will show up in the task command line usage.
+
+
+
+
+
+
+
+
+ Copyright 2006-2009, P. Beckingham. All rights reserved.
+
@@ -113,6 +114,21 @@
in the configuration file can be renamed.
+
+ Note that users of task prior to version 1.5.0 will need to add
+ the following six lines to their .taskrc file. See also the
+ README.1.5.0 file in the distribution for more details.
+
From 6d551357ff0f95b764c4af109782aac3641075a5 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sun, 15 Feb 2009 23:44:58 -0500
Subject: [PATCH 030/103] Packaging
- Began modification of script.txt in preparation for next movie!
- Added README.1.5.0 warning to configure.ac. Do you think people
will see it? And then read the file? I may need to provide an
automated solution.
---
configure.ac | 7 +++++++
script.txt | 14 +++++++++-----
2 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/configure.ac b/configure.ac
index a528345e1..0d4bf6556 100644
--- a/configure.ac
+++ b/configure.ac
@@ -73,3 +73,10 @@ AC_CHECK_FUNC(srandom, [AC_DEFINE([HAVE_SRANDOM], [1], [Found srandom])])
AC_CONFIG_FILES([Makefile src/Makefile])
AC_OUTPUT
+
+AC_MSG_NOTICE([...])
+AC_MSG_NOTICE([...])
+AC_MSG_NOTICE([Existing task users please read the README.1.5.0 file!])
+AC_MSG_NOTICE([...])
+AC_MSG_NOTICE([...])
+
diff --git a/script.txt b/script.txt
index e7d1913e6..db62d92a9 100644
--- a/script.txt
+++ b/script.txt
@@ -3,18 +3,18 @@
task add do laundry Let's add some tasks
I need to do laundry
-task add project:garage order dumpster Oh yeah, the dumpster
+task add project:garage order dumpster Oh yeah, I need to order the dumpster
-task add +phone tell mom i loveher Must call Mom (that "phone" there is a tag - they are
- useful for searching, categorizing)
+task add +phone tell mom i loveher Must call Mom (that "phone" there is a tag - they can
+ be useful for searching and categorizing)
task add +phone pro:garage schedule
goodwill pickup
-task ad +email pro:garage ask Tom if Notice I can abbreviating commands
+task ad +email pro:garage ask Tom if Notice I can abbreviate commands
he wants that old bkie
task ls Let's see what we've got
- I spelled bike wrong
+ Oh, I spelled bike wrong
task 5 /bkie/bike/
task ls That's better
@@ -97,6 +97,10 @@ task summary Summary shows progress on all projec
task history History shows general activity - how many added,
completed etc, by month
+task ghistory This report shows a histogram of tasks that were
+ added (in red), completed (in green) and deleted
+ (in yellow), all by month.
+
And that's it. There are more commands than this
covered in the online documentation, but this should give
the basic idea.
From bcf512e529f73e63384a6ac6462f8e04b84a0dfa Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Mon, 16 Feb 2009 21:09:00 -0500
Subject: [PATCH 031/103] Nag Rewrite
- Now uses a better escalating scale of "importance".
---
src/command.cpp | 1 -
src/task.cpp | 63 +++++++++++++++++++++++++++++++++++++++----------
2 files changed, 51 insertions(+), 13 deletions(-)
diff --git a/src/command.cpp b/src/command.cpp
index 084125bfd..9bd940fb2 100644
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -520,7 +520,6 @@ std::string handleStop (TDB& tdb, T& task, Config& conf)
original.setId (task.getId ());
tdb.modifyT (original);
- nag (tdb, task, conf);
return std::string ("");
}
else
diff --git a/src/task.cpp b/src/task.cpp
index 84a74b24c..88075102c 100644
--- a/src/task.cpp
+++ b/src/task.cpp
@@ -347,14 +347,56 @@ void nag (TDB& tdb, T& task, Config& conf)
std::vector pending;
tdb.allPendingT (pending);
- // Restrict to matching subset.
- std::vector matching;
- gatherNextTasks (tdb, task, conf, pending, matching);
+ // Counters.
+ int overdue = 0;
+ int high = 0;
+ int medium = 0;
+ int low = 0;
- foreach (i, matching)
- if (pending[*i].getId () == task.getId ())
- return;
+ // Scan all pending tasks.
+ foreach (t, pending)
+ {
+ if (t->getId () != task.getId ())
+ {
+ if (getDueState (t->getAttribute ("due")) == 2)
+ overdue++;
+ std::string priority = t->getAttribute ("priority");
+ if (priority.length ())
+ {
+ switch (priority[0])
+ {
+ case 'H': high++; break;
+ case 'M': medium++; break;
+ case 'L': low++; break;
+ }
+ }
+ }
+ }
+
+ // Scan the current task.
+ bool isOverdue = getDueState (task.getAttribute ("due")) == 2 ? true : false;
+
+ char pri = ' ';
+ std::string priority = task.getAttribute ("priority");
+ if (priority.length ())
+ pri = priority[0];
+
+ // General form is "if there are no more deserving tasks", suppress the nag.
+ std::cout << "# isOverdue = " << (isOverdue ? "true" : "false") << std::endl;
+ std::cout << "# pri = " << pri << std::endl;
+ std::cout << "# overdue = " << overdue << std::endl;
+ std::cout << "# high = " << high << std::endl;
+ std::cout << "# medium = " << medium << std::endl;
+ std::cout << "# low = " << low << std::endl;
+
+ if (isOverdue ) return;
+ if (pri == 'H' && !overdue ) return;
+ if (pri == 'M' && !overdue && !high ) return;
+ if (pri == 'L' && !overdue && !high && !medium ) return;
+ if (pri == ' ' && !overdue && !high && !medium && !low) return;
+
+ // All the excuses are made, all that remains is to nag the user.
std::cout << nagMessage << std::endl;
}
}
@@ -372,15 +414,12 @@ int getDueState (const std::string& due)
// rightNow is the current date + time.
Date rightNow;
+ Date midnight (rightNow.month (), rightNow.day (), rightNow.year ());
- // By performing this conversion, today is set up as the same date, but
- // midnight.
- Date today (rightNow.month (), rightNow.day (), rightNow.year ());
-
- if (dt < today)
+ if (dt < midnight)
return 2;
- Date nextweek = today + 7 * 86400;
+ Date nextweek = midnight + 7 * 86400;
if (dt < nextweek)
return 1;
}
From 72efddc0668c23dcbf01fc9faf8278f4aa66f27f Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Mon, 16 Feb 2009 21:35:26 -0500
Subject: [PATCH 032/103] Sample .taskrc - update
- Added default config variables for new reports.
- Removed README.1.5.0.
- Removed messages configure.ac
---
ChangeLog | 1 +
Makefile.am | 2 +-
README.1.5.0 | 15 ---------------
configure.ac | 6 ------
html/task.html | 16 +---------------
src/Config.cpp | 9 +++++++++
6 files changed, 12 insertions(+), 37 deletions(-)
delete mode 100644 README.1.5.0
diff --git a/ChangeLog b/ChangeLog
index 41018682f..9ffbbce77 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -18,6 +18,7 @@
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.
+ + New algorithm for determining when the "nag" message is displayed.
------ old releases ------------------------------
diff --git a/Makefile.am b/Makefile.am
index 549946a75..fb05a3a4a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,3 +1,3 @@
SUBDIRS = src
-EXTRA_DIST = DEVELOPERS README.1.5.0
+EXTRA_DIST = DEVELOPERS
diff --git a/README.1.5.0 b/README.1.5.0
deleted file mode 100644
index 23dc8bd5d..000000000
--- a/README.1.5.0
+++ /dev/null
@@ -1,15 +0,0 @@
-Task 1.5.0 has a custom reports feature. Three of the existing task reports
-are no longer implemented in task, and need to be added as custom reports.
-Simply copy the following six lines into your existing .taskrc file.
-
-New task users need not do this - task will create an initial .taskrc file
-on first startup.
-
-
-report.long.columns=id,project,priority,entry,start,due,age,tags,description
-report.long.sort=due+,priority-,project+
-report.list.columns=id,project,priority,due,active,age,description
-report.list.sort=due+,priority-,project+
-report.ls.columns=id,project,priority,description
-report.ls.sort=priority-,project+
-
diff --git a/configure.ac b/configure.ac
index 0d4bf6556..d6e95db0f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -74,9 +74,3 @@ AC_CHECK_FUNC(srandom, [AC_DEFINE([HAVE_SRANDOM], [1], [Found srandom])])
AC_CONFIG_FILES([Makefile src/Makefile])
AC_OUTPUT
-AC_MSG_NOTICE([...])
-AC_MSG_NOTICE([...])
-AC_MSG_NOTICE([Existing task users please read the README.1.5.0 file!])
-AC_MSG_NOTICE([...])
-AC_MSG_NOTICE([...])
-
diff --git a/html/task.html b/html/task.html
index 696a0a6b5..03c8eee60 100644
--- a/html/task.html
+++ b/html/task.html
@@ -112,23 +112,9 @@
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.
+
New algorithm for determining when the "nag" message is displayed.
-
- Note that users of task prior to version 1.5.0 will need to add
- the following six lines to their .taskrc file. See also the
- README.1.5.0 file in the distribution for more details.
-
diff --git a/src/Config.cpp b/src/Config.cpp
index f63a58700..3f46613a0 100644
--- a/src/Config.cpp
+++ b/src/Config.cpp
@@ -38,6 +38,15 @@
////////////////////////////////////////////////////////////////////////////////
Config::Config ()
{
+ // These are default (but overridable) reports.
+ (*this)["report.large.columns"] = "id,uuid,project,priority,entry,start,due,age,active,tags,description";
+ (*this)["report.large.sort"] = "due+,priority-,project+";
+ (*this)["report.long.columns"] = "id,project,priority,entry,start,due,age,tags,description";
+ (*this)["report.long.sort"] = "due+,priority-,project+";
+ (*this)["report.list.columns"] = "id,project,priority,due,active,age,description";
+ (*this)["report.list.sort"] = "due+,priority-,project+";
+ (*this)["report.ls.columns"] = "id,project,priority,description";
+ (*this)["report.ls.sort"] = "priority-,project+";
}
////////////////////////////////////////////////////////////////////////////////
From 92ba36bdec79d14c2e64fc9f5aa1c91273fe27ac Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Mon, 16 Feb 2009 23:12:04 -0500
Subject: [PATCH 033/103] Unit Tests - add, delete, info, ///
- Began set of high-level integration tests, in Perl.
---
src/Config.cpp | 2 --
src/tests/add.t | 72 +++++++++++++++++++++++++++++++++++++++++++++++
src/tests/basic.t | 57 +++++++++++++++++++++++++++++++++++++
src/tests/in | 15 ----------
4 files changed, 129 insertions(+), 17 deletions(-)
create mode 100755 src/tests/add.t
create mode 100755 src/tests/basic.t
delete mode 100755 src/tests/in
diff --git a/src/Config.cpp b/src/Config.cpp
index 3f46613a0..fee5cf39a 100644
--- a/src/Config.cpp
+++ b/src/Config.cpp
@@ -39,8 +39,6 @@
Config::Config ()
{
// These are default (but overridable) reports.
- (*this)["report.large.columns"] = "id,uuid,project,priority,entry,start,due,age,active,tags,description";
- (*this)["report.large.sort"] = "due+,priority-,project+";
(*this)["report.long.columns"] = "id,project,priority,entry,start,due,age,tags,description";
(*this)["report.long.sort"] = "due+,priority-,project+";
(*this)["report.list.columns"] = "id,project,priority,due,active,age,description";
diff --git a/src/tests/add.t b/src/tests/add.t
new file mode 100755
index 000000000..26a82f0ee
--- /dev/null
+++ b/src/tests/add.t
@@ -0,0 +1,72 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 14;
+
+# Create the rc file.
+if (open my $fh, '>', 'add.rc')
+{
+ print $fh "data.location=.\n";
+ close $fh;
+ ok (-r 'add.rc', 'Created add.rc');
+}
+
+# Test the add command.
+my $output = qx{../task rc:add.rc add This is a test; ../task rc:add.rc info 1};
+like ($output, qr/ID\s+1\n/, 'add ID');
+like ($output, qr/Description\s+This is a test\n/, 'add ID');
+like ($output, qr/Status\s+Pending\n/, 'add Pending');
+like ($output, qr/UUID\s+[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}\n/, 'add UUID');
+
+# Test the /// modifier.
+$output = qx{../task rc:add.rc 1 /test/TEST/; ../task rc:add.rc 1 "/is //"; ../task rc:add.rc info 1};
+like ($output, qr/ID\s+1\n/, 'add ID');
+like ($output, qr/Status\s+Pending\n/, 'add Pending');
+like ($output, qr/Description\s+This a TEST\n/, 'add ID');
+
+# Test delete.
+$output = qx{../task rc:add.rc delete 1; ../task rc:add.rc info 1};
+like ($output, qr/ID\s+1\n/, 'add ID');
+like ($output, qr/Status\s+Deleted\n/, 'add Deleted');
+
+# Test undelete.
+$output = qx{../task rc:add.rc undelete 1; ../task rc:add.rc info 1};
+like ($output, qr/ID\s+1\n/, 'add ID');
+like ($output, qr/Status\s+Pending\n/, 'add Pending');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pendind.data', 'Removed pending.data');
+
+unlink 'add.rc';
+ok (!-r 'add.rc', 'Removed add.rc');
+
+exit 0;
+
diff --git a/src/tests/basic.t b/src/tests/basic.t
new file mode 100755
index 000000000..e369b773d
--- /dev/null
+++ b/src/tests/basic.t
@@ -0,0 +1,57 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 7;
+
+# Create the rc file.
+if (open my $fh, '>', 'basic.rc')
+{
+ print $fh "data.location=.\n";
+ close $fh;
+ ok (-r 'basic.rc', 'Created basic.rc');
+}
+
+# Test the usage command.
+my $output = qx{../task rc:basic.rc};
+like ($output, qr/Usage: task/, 'usage');
+like ($output, qr/http:\/\/www\.beckingham\.net\/task\.html/, 'usage - url');
+
+# Test the version command.
+$output = qx{../task rc:basic.rc version};
+like ($output, qr/task \d+\.\d+\.\d+/, 'version - task version number');
+like ($output, qr/ABSOLUTELY NO WARRANTY/, 'version - warranty');
+like ($output, qr/http:\/\/www\.beckingham\.net\/task\.html/, 'version - url');
+
+# Cleanup.
+unlink 'basic.rc';
+ok (!-r 'basic.rc', 'Removed basic.rc');
+
+exit 0;
+
diff --git a/src/tests/in b/src/tests/in
deleted file mode 100755
index 761c1f877..000000000
--- a/src/tests/in
+++ /dev/null
@@ -1,15 +0,0 @@
-./task add monday due:monday
-./task add tuesday due:tuesday
-./task add wednesday due:wednesday
-./task add thursday due:thursday
-./task add friday due:friday
-./task add saturday due:saturday
-./task add sunday due:sunday
-./task add yesterday due:yesterday
-./task add today due:today
-./task add tomorrow due:tomorrow
-./task add eow due:eow
-./task add eom due:eom
-./task add eoy due:eoy
-./task add 21st due:21st
-
From e2fca47a2711d945a7874655bc14c7621d94a21f Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Fri, 20 Feb 2009 21:08:39 -0500
Subject: [PATCH 034/103] Typo
- Added missing "http://" to "www.samurize.com", at the suggestion
of Carlos Yoder.
---
html/shadow.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/html/shadow.html b/html/shadow.html
index 6b66de763..e6ae6f07c 100644
--- a/html/shadow.html
+++ b/html/shadow.html
@@ -43,7 +43,7 @@
This means there is always a current version of the task
report kept in a text file. Products such as
- Samurize,
+ Samurize,
MkConsole,
or
GeekTool
From f9272773ac52c7bb308f68f7e91ca5895df6845d Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sat, 21 Feb 2009 17:24:07 -0500
Subject: [PATCH 035/103] Credit
- Added Carlos Yoder to AUTHORS, for his contribution.
- Added Russell Friesenhahn to AUTHORS, for his contribution.
---
AUTHORS | 2 ++
1 file changed, 2 insertions(+)
diff --git a/AUTHORS b/AUTHORS
index 027de8b31..33a5b9368 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -18,4 +18,6 @@ With thanks to:
Vincent Fleuranceau
T. Charles Yun
ArchiMark
+ Carlos Yoder
+ Russell Friesenhahn
From 060516123678eb5032fe6b1d4e1065adcd28b10e Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Mon, 23 Feb 2009 10:38:01 -0500
Subject: [PATCH 036/103] Updated OS Compatibility List
- Fedora Core 10
- Ubuntu 8.10 Intrepid Ibex
---
html/task.html | 2 ++
1 file changed, 2 insertions(+)
diff --git a/html/task.html b/html/task.html
index 03c8eee60..3f383af5c 100644
--- a/html/task.html
+++ b/html/task.html
@@ -129,8 +129,10 @@
OS X 10.5 Leopard
Fedora Core 8
Fedora Core 9
+
Fedora Core 10
Ubuntu 7 Feisty Fawn
Ubuntu 8 Hardy Heron
+
Ubuntu 8.10 Intrepid Ibex
Solaris 10
Cygwin 1.5.25-14
From 8c484a333d51978c38a6a4dbf5a5573b9c62cda7 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Mon, 23 Feb 2009 22:59:17 -0500
Subject: [PATCH 037/103] Documentation Update
- Added folks to AUTHORS file.
- Added Fedora Core 10, Ubuntu 8.10 Intrepid Ibex to compatibility
list.
---
AUTHORS | 3 +++
html/links.html | 26 ++++++++++++++++++++++++++
2 files changed, 29 insertions(+)
diff --git a/AUTHORS b/AUTHORS
index 33a5b9368..9fae397e7 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -5,6 +5,7 @@ Contributing Authors:
Damian Glenny
Andy Lester
H. İbrahim Güngör
+ Stefan Dorn
With thanks to:
Eugene Kramer
@@ -20,4 +21,6 @@ With thanks to:
ArchiMark
Carlos Yoder
Russell Friesenhahn
+ Paolo Marsi
+ Eric Farris
diff --git a/html/links.html b/html/links.html
index 817dbacd4..77dc5a15b 100644
--- a/html/links.html
+++ b/html/links.html
@@ -37,6 +37,32 @@
Task links from around the web...
From 76c9d3565c985dc0901567c51700dbdb8d0f8efa Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Tue, 24 Feb 2009 22:27:51 -0500
Subject: [PATCH 038/103] Documentation Update
- Added paragraph tags. Don't know why, but the rendering was odd.
---
html/task.html | 26 ++++++++++++++------------
1 file changed, 14 insertions(+), 12 deletions(-)
diff --git a/html/task.html b/html/task.html
index 3f383af5c..f3f309b08 100644
--- a/html/task.html
+++ b/html/task.html
@@ -124,18 +124,20 @@
Task has been built from source and tested in the following environments:
-
-
OS X 10.4 Tiger
-
OS X 10.5 Leopard
-
Fedora Core 8
-
Fedora Core 9
-
Fedora Core 10
-
Ubuntu 7 Feisty Fawn
-
Ubuntu 8 Hardy Heron
-
Ubuntu 8.10 Intrepid Ibex
-
Solaris 10
-
Cygwin 1.5.25-14
-
+
+
+
OS X 10.4 Tiger
+
OS X 10.5 Leopard
+
Fedora Core 8
+
Fedora Core 9
+
Fedora Core 10
+
Ubuntu 7 Feisty Fawn
+
Ubuntu 8 Hardy Heron
+
Ubuntu 8.10 Intrepid Ibex
+
Solaris 10
+
Cygwin 1.5.25-14
+
+
If you have difficulties building task, have found a bug, have a
From 59a014d86601a419be8818673ba5dd4865a609dd Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sun, 1 Mar 2009 23:52:28 -0500
Subject: [PATCH 039/103] Unit Tests - nag
- Added unit tests to exercise the nag option.
---
src/tests/nag.t | 66 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
create mode 100755 src/tests/nag.t
diff --git a/src/tests/nag.t b/src/tests/nag.t
new file mode 100755
index 000000000..e6ff4a211
--- /dev/null
+++ b/src/tests/nag.t
@@ -0,0 +1,66 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 9;
+
+# Create the rc file.
+if (open my $fh, '>', 'nag.rc')
+{
+ print $fh "data.location=.\n",
+ "nag=NAG\n";
+ close $fh;
+ ok (-r 'nag.rc', 'Created add.rc');
+}
+
+my $setup = "../task rc:nag.rc add due:yesterday one;"
+ . "../task rc:nag.rc add due:tomorrow two;"
+ . "../task rc:nag.rc add priority:H three;"
+ . "../task rc:nag.rc add priority:M four;"
+ . "../task rc:nag.rc add priority:L five;"
+ . "../task rc:nag.rc add six;";
+qx{$setup};
+
+my $output = qx{../task rc:nag.rc do 6};
+like (qx{../task rc:nag.rc do 6}, qr/NAG/, 'do pri: -> nag');
+like (qx{../task rc:nag.rc do 5}, qr/NAG/, 'do pri:L -> nag');
+like (qx{../task rc:nag.rc do 4}, qr/NAG/, 'do pri:M-> nag');
+like (qx{../task rc:nag.rc do 3}, qr/NAG/, 'do pri:H-> nag');
+like (qx{../task rc:nag.rc do 2}, qr/NAG/, 'do due:tomorrow -> nag');
+ok (qx{../task rc:nag.rc do 1} !~ qr/NAG/, 'do due:yesterday -> no nag');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pendind.data', 'Removed pending.data');
+
+unlink 'nag.rc';
+ok (!-r 'nag.rc', 'Removed nag.rc');
+
+exit 0;
+
From 6e956b45ad0091e4a8ec3b1082f9266e425d86e9 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Mon, 2 Mar 2009 00:44:28 -0500
Subject: [PATCH 040/103] Code Cleanup
- Fixed typo in unit test
---
src/tests/nag.t | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/tests/nag.t b/src/tests/nag.t
index e6ff4a211..53c5c92ba 100755
--- a/src/tests/nag.t
+++ b/src/tests/nag.t
@@ -36,7 +36,7 @@ if (open my $fh, '>', 'nag.rc')
print $fh "data.location=.\n",
"nag=NAG\n";
close $fh;
- ok (-r 'nag.rc', 'Created add.rc');
+ ok (-r 'nag.rc', 'Created nag.rc');
}
my $setup = "../task rc:nag.rc add due:yesterday one;"
From 1e704001437c416fd02808e24b69b488989b5f89 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Mon, 2 Mar 2009 23:47:41 -0500
Subject: [PATCH 041/103] Shadow File Rewrite
- No longer writes shadow files based on TDB onChange trigger.
- Addressed bug whereby adding a recurring task trigger a shadow
file rewrite, which in turn performs trigger another rewrite...
---
src/TDB.cpp | 20 -------
src/TDB.h | 4 --
src/report.cpp | 1 +
src/task.cpp | 151 ++++++++++++++++++++++---------------------------
src/task.h | 4 +-
5 files changed, 72 insertions(+), 108 deletions(-)
diff --git a/src/TDB.cpp b/src/TDB.cpp
index bce2d6e4e..98a67e119 100644
--- a/src/TDB.cpp
+++ b/src/TDB.cpp
@@ -308,7 +308,6 @@ bool TDB::overwritePending (std::vector & all)
fputs (it->compose ().c_str (), out);
fclose (out);
- dbChanged ();
return true;
}
@@ -329,7 +328,6 @@ bool TDB::writePending (const T& t)
fputs (t.compose ().c_str (), out);
fclose (out);
- dbChanged ();
return true;
}
@@ -350,8 +348,6 @@ bool TDB::writeCompleted (const T& t)
fputs (t.compose ().c_str (), out);
fclose (out);
- // Note: No call to dbChanged here because this call never occurs by itself.
- // It is always accompanied by an overwritePending call.
return true;
}
@@ -436,20 +432,4 @@ int TDB::nextId ()
}
////////////////////////////////////////////////////////////////////////////////
-void TDB::onChange (void (*callback)())
-{
- if (callback)
- mOnChange.push_back (callback);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Iterate over callbacks.
-void TDB::dbChanged ()
-{
- foreach (i, mOnChange)
- if (*i)
- (**i) ();
-}
-
-////////////////////////////////////////////////////////////////////////////////
diff --git a/src/TDB.h b/src/TDB.h
index e654acc05..b354d97f3 100644
--- a/src/TDB.h
+++ b/src/TDB.h
@@ -51,21 +51,17 @@ public:
int gc ();
int nextId ();
- void onChange (void (*)());
-
private:
bool lock (FILE*) const;
bool overwritePending (std::vector &);
bool writePending (const T&);
bool writeCompleted (const T&);
bool readLockedFile (const std::string&, std::vector &) const;
- void dbChanged ();
private:
std::string mPendingFile;
std::string mCompletedFile;
int mId;
- std::vector mOnChange;
};
#endif
diff --git a/src/report.cpp b/src/report.cpp
index 8c4c1664d..a43d50706 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -2260,6 +2260,7 @@ std::string handleCustomReport (
// Load all pending tasks.
std::vector tasks;
tdb.allPendingT (tasks);
+ handleRecurrence (tdb, tasks);
// Apply filters.
{
diff --git a/src/task.cpp b/src/task.cpp
index 88075102c..ae94d6c2d 100644
--- a/src/task.cpp
+++ b/src/task.cpp
@@ -46,11 +46,6 @@
#include
#endif
-////////////////////////////////////////////////////////////////////////////////
-// Globals for exclusive use by callback function.
-static TDB* gTdb = NULL;
-static Config* gConf = NULL;
-
////////////////////////////////////////////////////////////////////////////////
static void shortUsage (Config& conf)
{
@@ -289,7 +284,6 @@ int main (int argc, char** argv)
// Load the config file from the home directory. If the file cannot be
// found, offer to create a sample one.
Config conf;
- gConf = &conf;
loadConfFile (argc, argv, conf);
// When redirecting output to a file, do not use color, curses.
@@ -300,11 +294,10 @@ int main (int argc, char** argv)
}
TDB tdb;
- gTdb = &tdb;
std::string dataLocation = expandPath (conf.get ("data.location"));
tdb.dataDirectory (dataLocation);
- // Set up TDB callback.
+ // Check for silly shadow file settings.
std::string shadowFile = expandPath (conf.get ("shadow.file"));
if (shadowFile != "")
{
@@ -315,8 +308,6 @@ int main (int argc, char** argv)
if (shadowFile == dataLocation + "/completed.data")
throw std::string ("Configuration variable 'shadow.file' is set to "
"overwrite your completed tasks. Please change it.");
-
- tdb.onChange (&onChangeCallback);
}
std::cout << runTaskCommand (argc, argv, tdb, conf);
@@ -383,12 +374,12 @@ void nag (TDB& tdb, T& task, Config& conf)
pri = priority[0];
// General form is "if there are no more deserving tasks", suppress the nag.
- std::cout << "# isOverdue = " << (isOverdue ? "true" : "false") << std::endl;
- std::cout << "# pri = " << pri << std::endl;
- std::cout << "# overdue = " << overdue << std::endl;
- std::cout << "# high = " << high << std::endl;
- std::cout << "# medium = " << medium << std::endl;
- std::cout << "# low = " << low << std::endl;
+ std::cout << "# task.isOverdue = " << (isOverdue ? "true" : "false") << std::endl;
+ std::cout << "# task.pri = " << pri << std::endl;
+ std::cout << "# task.overdue = " << overdue << std::endl;
+ std::cout << "# pending.high = " << high << std::endl;
+ std::cout << "# pending.medium = " << medium << std::endl;
+ std::cout << "# pending.low = " << low << std::endl;
if (isOverdue ) return;
if (pri == 'H' && !overdue ) return;
@@ -711,51 +702,45 @@ void updateRecurrenceMask (
}
////////////////////////////////////////////////////////////////////////////////
-// Using gTdb and gConf, generate a report.
-void onChangeCallback ()
+void updateShadowFile (TDB& tdb, Config& conf)
{
try
{
- if (gConf && gTdb)
+ // Determine if shadow file is enabled.
+ std::string shadowFile = expandPath (conf.get ("shadow.file"));
+ if (shadowFile != "")
{
- // Determine if shadow file is enabled.
- std::string shadowFile = expandPath (gConf->get ("shadow.file"));
- if (shadowFile != "")
+ std::string oldCurses = conf.get ("curses");
+ std::string oldColor = conf.get ("color");
+ conf.set ("curses", "off");
+ conf.set ("color", "off");
+
+ // Run report. Use shadow.command, using default.command as a fallback
+ // with "list" as a default.
+ std::string command = conf.get ("shadow.command",
+ conf.get ("default.command", "list"));
+ std::vector args;
+ split (args, command, ' ');
+ std::string result = runTaskCommand (args, tdb, conf);
+
+ std::ofstream out (shadowFile.c_str ());
+ if (out.good ())
{
- std::string oldCurses = gConf->get ("curses");
- std::string oldColor = gConf->get ("color");
- gConf->set ("curses", "off");
- gConf->set ("color", "off");
-
- // Run report. Use shadow.command, using default.command as a fallback
- // with "list" as a default.
- std::string command = gConf->get ("shadow.command",
- gConf->get ("default.command", "list"));
- std::vector args;
- split (args, command, ' ');
- std::string result = runTaskCommand (args, *gTdb, *gConf);
-
- std::ofstream out (shadowFile.c_str ());
- if (out.good ())
- {
- out << result;
- out.close ();
- }
- else
- throw std::string ("Could not write file '") + shadowFile + "'";
-
- gConf->set ("curses", oldCurses);
- gConf->set ("color", oldColor);
+ out << result;
+ out.close ();
}
else
- throw std::string ("No specified shadow file '") + shadowFile + "'.";
+ throw std::string ("Could not write file '") + shadowFile + "'";
- // Optionally display a notification that the shadow file was updated.
- if (gConf->get (std::string ("shadow.notify"), false))
- std::cout << "[Shadow file '" << shadowFile << "' updated]" << std::endl;
+ conf.set ("curses", oldCurses);
+ conf.set ("color", oldColor);
}
else
- throw std::string ("Internal error (TDB/Config).");
+ throw std::string ("No specified shadow file '") + shadowFile + "'.";
+
+ // Optionally display a notification that the shadow file was updated.
+ if (conf.get (std::string ("shadow.notify"), false))
+ std::cout << "[Shadow file '" << shadowFile << "' updated]" << std::endl;
}
catch (std::string& error)
@@ -775,13 +760,14 @@ std::string runTaskCommand (
char** argv,
TDB& tdb,
Config& conf,
- bool gc /* = true */)
+ bool gc /* = true */,
+ bool shadow /* = true */)
{
std::vector args;
for (int i = 1; i < argc; ++i)
args.push_back (argv[i]);
- return runTaskCommand (args, tdb, conf, gc);
+ return runTaskCommand (args, tdb, conf, gc, shadow);
}
////////////////////////////////////////////////////////////////////////////////
@@ -789,7 +775,8 @@ std::string runTaskCommand (
std::vector & args,
TDB& tdb,
Config& conf,
- bool gc /* = false */)
+ bool gc /* = false */,
+ bool shadow /* = false */)
{
// If argc == 1 and the default.command configuration variable is set,
// then use that, otherwise stick with argc/argv.
@@ -810,34 +797,34 @@ std::string runTaskCommand (
std::string out = "";
- if (command == "" && task.getId ()) { handleModify (tdb, task, conf ); }
- else if (command == "add") { handleAdd (tdb, task, conf ); }
- else if (command == "done") { handleDone (tdb, task, conf ); }
- else if (command == "export") { handleExport (tdb, task, conf ); }
- else if (command == "projects") { out = handleProjects (tdb, task, conf ); }
- else if (command == "tags") { out = handleTags (tdb, task, conf ); }
- else if (command == "info") { out = handleInfo (tdb, task, conf ); }
- else if (command == "undelete") { out = handleUndelete (tdb, task, conf ); }
- else if (command == "delete") { out = handleDelete (tdb, task, conf ); }
- else if (command == "start") { out = handleStart (tdb, task, conf ); }
- else if (command == "stop") { out = handleStop (tdb, task, conf ); }
- else if (command == "undo") { out = handleUndo (tdb, task, conf ); }
- else if (command == "stats") { out = handleReportStats (tdb, task, conf ); }
- else if (command == "completed") { if (gc) tdb.gc (); out = handleCompleted (tdb, task, conf ); } // TODO replace with Custom
- else if (command == "summary") { if (gc) tdb.gc (); out = handleReportSummary (tdb, task, conf ); }
- else if (command == "next") { if (gc) tdb.gc (); out = handleReportNext (tdb, task, conf ); } // TODO replace with Custom
- else if (command == "history") { if (gc) tdb.gc (); out = handleReportHistory (tdb, task, conf ); }
- else if (command == "ghistory") { if (gc) tdb.gc (); out = handleReportGHistory (tdb, task, conf ); }
- else if (command == "calendar") { if (gc) tdb.gc (); out = handleReportCalendar (tdb, task, conf ); }
- else if (command == "active") { if (gc) tdb.gc (); out = handleReportActive (tdb, task, conf ); } // TODO replace with Custom
- else if (command == "overdue") { if (gc) tdb.gc (); out = handleReportOverdue (tdb, task, conf ); } // TODO replace with Custom
- else if (command == "oldest") { if (gc) tdb.gc (); out = handleReportOldest (tdb, task, conf ); } // TODO replace with Custom
- else if (command == "newest") { if (gc) tdb.gc (); out = handleReportNewest (tdb, task, 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 ); }
- else if (isCustomReport (command)) { if (gc) tdb.gc (); out = handleCustomReport (tdb, task, conf, command); } // New Custom reports
- else { shortUsage ( conf ); }
+ if (command == "" && task.getId ()) { handleModify (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); }
+ else if (command == "add") { handleAdd (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); }
+ else if (command == "done") { handleDone (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); }
+ else if (command == "export") { handleExport (tdb, task, conf ); }
+ else if (command == "projects") { out = handleProjects (tdb, task, conf ); }
+ else if (command == "tags") { out = handleTags (tdb, task, conf ); }
+ else if (command == "info") { out = handleInfo (tdb, task, conf ); }
+ else if (command == "undelete") { out = handleUndelete (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); }
+ else if (command == "delete") { out = handleDelete (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); }
+ else if (command == "start") { out = handleStart (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); }
+ else if (command == "stop") { out = handleStop (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); }
+ else if (command == "undo") { out = handleUndo (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); }
+ else if (command == "stats") { out = handleReportStats (tdb, task, conf ); }
+ else if (command == "completed") { if (gc) tdb.gc (); out = handleCompleted (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } // TODO replace with Custom
+ else if (command == "summary") { if (gc) tdb.gc (); out = handleReportSummary (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); }
+ else if (command == "next") { if (gc) tdb.gc (); out = handleReportNext (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } // TODO replace with Custom
+ else if (command == "history") { if (gc) tdb.gc (); out = handleReportHistory (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); }
+ else if (command == "ghistory") { if (gc) tdb.gc (); out = handleReportGHistory (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 == "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 ); }
+ else if (isCustomReport (command)) { if (gc) tdb.gc (); out = handleCustomReport (tdb, task, conf, command); if (shadow) updateShadowFile (tdb, conf); } // New Custom reports
+ else { shortUsage ( conf ); }
return out;
}
diff --git a/src/task.h b/src/task.h
index 151794c7d..03a5d5f7d 100644
--- a/src/task.h
+++ b/src/task.h
@@ -69,8 +69,8 @@ bool generateDueDates (T&, std::vector &);
Date getNextRecurrence (Date&, std::string&);
void updateRecurrenceMask (TDB&, std::vector &, T&);
void onChangeCallback ();
-std::string runTaskCommand (int, char**, TDB&, Config&, bool gc = true);
-std::string runTaskCommand (std::vector &, TDB&, Config&, bool gc = false);
+std::string runTaskCommand (int, char**, TDB&, Config&, bool gc = true, bool shadow = true);
+std::string runTaskCommand (std::vector &, TDB&, Config&, bool gc = false, bool shadow = false);
// command.cpp
void handleAdd (TDB&, T&, Config&);
From a1b7516cf894a9eac4291bec03028eafd259ce2f Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Mon, 2 Mar 2009 23:49:13 -0500
Subject: [PATCH 042/103] Sort Algorithm Fix
- The sort algorithm (Combsort11) was broken because it didn't
consider all the possible variations of present/missing, same/
different combinations of data, when performing a compare. This
led to an unstable sort, which is an infinite loop in Combsort11.
---
src/Table.cpp | 66 +++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 53 insertions(+), 13 deletions(-)
diff --git a/src/Table.cpp b/src/Table.cpp
index f62fb2eae..2bf97be2b 100644
--- a/src/Table.cpp
+++ b/src/Table.cpp
@@ -764,6 +764,32 @@ void Table::optimize (std::string& output)
////////////////////////////////////////////////////////////////////////////////
// Combsort11, with O(n log n) average, O(n log n) worst case performance.
+//
+// function combsort11(array input)
+// gap := input.size
+//
+// loop until gap <= 1 and swaps = 0
+// if gap > 1
+// gap := gap / 1.3
+// if gap = 10 or gap = 9
+// gap := 11
+// end if
+// end if
+//
+// i := 0
+// swaps := 0
+//
+// loop until i + gap >= input.size
+// if input[i] > input[i+gap]
+// swap(input[i], input[i+gap])
+// swaps := 1
+// end if
+// i := i + 1
+// end loop
+//
+// end loop
+// end function
+
#define SWAP \
{ \
int temp = order[r]; \
@@ -776,7 +802,7 @@ void Table::sort (std::vector & order)
int gap = order.size ();
int swaps = 1;
- while (gap > 1 || swaps != 0)
+ while (gap > 1 || swaps > 0)
{
if (gap > 1)
{
@@ -797,10 +823,28 @@ void Table::sort (std::vector & order)
Grid::Cell* left = mData.byRow (order[r], mSortColumns[c]);
Grid::Cell* right = mData.byRow (order[r + gap], mSortColumns[c]);
- if (left == NULL && right != NULL)
- SWAP
- if (left && right && *left != *right)
+ // Data takes precedence over missing data.
+ if (left == NULL && right != NULL)
+ {
+ SWAP
+ break;
+ }
+
+ // No data - try comparing the next column.
+ else if (left == NULL && right == NULL)
+ {
+ keepScanning = true;
+ }
+
+ // Identical data - try comparing the next column.
+ else if (left && right && *left == *right)
+ {
+ keepScanning = true;
+ }
+
+ // Differing data - do a proper comparison.
+ else if (left && right && *left != *right)
{
switch (mSortOrder[mSortColumns[c]])
{
@@ -861,24 +905,20 @@ void Table::sort (std::vector & order)
break;
case ascendingPriority:
- if (((std::string)*left == "" && (std::string)*right != "") ||
- ((std::string)*left == "M" && (std::string)*right == "L") ||
- ((std::string)*left == "H" && ((std::string)*right == "L" || (std::string)*right == "M")))
+ if (((std::string)*left == "" && (std::string)*right != "") ||
+ ((std::string)*left == "M" && (std::string)*right == "L") ||
+ ((std::string)*left == "H" && ((std::string)*right == "L" || (std::string)*right == "M")))
SWAP
break;
case descendingPriority:
- if (((std::string)*left == "" && (std::string)*right != "") ||
+ if (((std::string)*left == "" && (std::string)*right != "") ||
((std::string)*left == "L" && ((std::string)*right == "M" || (std::string)*right == "H")) ||
- ((std::string)*left == "M" && (std::string)*right == "H"))
+ ((std::string)*left == "M" && (std::string)*right == "H"))
SWAP
break;
}
-
- break;
}
- else
- keepScanning = true;
}
++r;
From 8157c729d62e126d2ba0eb793891ff3fccc0b8bf Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Tue, 3 Mar 2009 00:08:06 -0500
Subject: [PATCH 043/103] Unit Tests - bug_sort
- Added a unit test to cover the bug whereby certain combinations
of adding tasks causes Table::sort to loop indefinitely.
---
src/tests/bug_sort.t | 62 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 62 insertions(+)
create mode 100755 src/tests/bug_sort.t
diff --git a/src/tests/bug_sort.t b/src/tests/bug_sort.t
new file mode 100755
index 000000000..4b9c4973a
--- /dev/null
+++ b/src/tests/bug_sort.t
@@ -0,0 +1,62 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 5;
+
+# Create the rc file.
+if (open my $fh, '>', 'bug_sort.rc')
+{
+ print $fh "data.location=.\n";
+ close $fh;
+ ok (-r 'bug_sort.rc', 'Created bug_sort.rc');
+}
+
+my $setup = "../task rc:bug_sort.rc add one;"
+ . "../task rc:bug_sort.rc add two;"
+ . "../task rc:bug_sort.rc add three recur:daily due:eom;";
+qx{$setup};
+
+my $output = qx{../task rc:bug_sort.rc list};
+#diag ($output);
+like ($output, qr/three.*(?:one.*two|two.*one)/msi, 'list did not hang');
+
+qx{../task rc:bug_sort.rc 1 priority:H};
+$output = qx{../task rc:bug_sort.rc list};
+like ($output, qr/three.*one.*two/msi, 'list did not hang after pri:H on 1');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pendind.data', 'Removed pending.data');
+
+unlink 'bug_sort.rc';
+ok (!-r 'bug_sort.rc', 'Removed bug_sort.rc');
+
+exit 0;
+
From 964d04322ca9d6972837bd6e79bbbcbdee5913fe Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Tue, 3 Mar 2009 00:46:02 -0500
Subject: [PATCH 044/103] Bug Fix - nag
- Implemented new nag algorithm, and debugged why it then broke.
---
src/task.cpp | 35 +++++++++++++++++++----------------
src/tests/nag.t | 1 -
2 files changed, 19 insertions(+), 17 deletions(-)
diff --git a/src/task.cpp b/src/task.cpp
index ae94d6c2d..727db1f16 100644
--- a/src/task.cpp
+++ b/src/task.cpp
@@ -334,20 +334,31 @@ void nag (TDB& tdb, T& task, Config& conf)
std::string nagMessage = conf.get ("nag", std::string (""));
if (nagMessage != "")
{
- // Load all pending.
+ // Load all pending tasks.
std::vector pending;
tdb.allPendingT (pending);
// Counters.
- int overdue = 0;
- int high = 0;
- int medium = 0;
- int low = 0;
+ int overdue = 0;
+ int high = 0;
+ int medium = 0;
+ int low = 0;
+ bool isOverdue = false;
+ char pri = ' ';
// Scan all pending tasks.
foreach (t, pending)
{
- if (t->getId () != task.getId ())
+ if (t->getId () == task.getId ())
+ {
+ if (getDueState (t->getAttribute ("due")) == 2)
+ isOverdue = true;
+
+ std::string priority = t->getAttribute ("priority");
+ if (priority.length ())
+ pri = priority[0];
+ }
+ else if (t->getStatus () == T::pending)
{
if (getDueState (t->getAttribute ("due")) == 2)
overdue++;
@@ -365,21 +376,15 @@ void nag (TDB& tdb, T& task, Config& conf)
}
}
- // Scan the current task.
- bool isOverdue = getDueState (task.getAttribute ("due")) == 2 ? true : false;
-
- char pri = ' ';
- std::string priority = task.getAttribute ("priority");
- if (priority.length ())
- pri = priority[0];
-
// General form is "if there are no more deserving tasks", suppress the nag.
+/*
std::cout << "# task.isOverdue = " << (isOverdue ? "true" : "false") << std::endl;
std::cout << "# task.pri = " << pri << std::endl;
std::cout << "# task.overdue = " << overdue << std::endl;
std::cout << "# pending.high = " << high << std::endl;
std::cout << "# pending.medium = " << medium << std::endl;
std::cout << "# pending.low = " << low << std::endl;
+*/
if (isOverdue ) return;
if (pri == 'H' && !overdue ) return;
@@ -735,8 +740,6 @@ void updateShadowFile (TDB& tdb, Config& conf)
conf.set ("curses", oldCurses);
conf.set ("color", oldColor);
}
- else
- throw std::string ("No specified shadow file '") + shadowFile + "'.";
// Optionally display a notification that the shadow file was updated.
if (conf.get (std::string ("shadow.notify"), false))
diff --git a/src/tests/nag.t b/src/tests/nag.t
index 53c5c92ba..d9dc94d76 100755
--- a/src/tests/nag.t
+++ b/src/tests/nag.t
@@ -47,7 +47,6 @@ my $setup = "../task rc:nag.rc add due:yesterday one;"
. "../task rc:nag.rc add six;";
qx{$setup};
-my $output = qx{../task rc:nag.rc do 6};
like (qx{../task rc:nag.rc do 6}, qr/NAG/, 'do pri: -> nag');
like (qx{../task rc:nag.rc do 5}, qr/NAG/, 'do pri:L -> nag');
like (qx{../task rc:nag.rc do 4}, qr/NAG/, 'do pri:M-> nag');
From 5c89c0f1be2e3fd998b5928ebbb81607f6375b3d Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Tue, 3 Mar 2009 00:53:32 -0500
Subject: [PATCH 045/103] Documentation Update
- Modified ChangeLog and task.html to reflect new bug fixes.
---
ChangeLog | 5 +++++
html/task.html | 5 +++++
2 files changed, 10 insertions(+)
diff --git a/ChangeLog b/ChangeLog
index 9ffbbce77..e85e949a0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -18,7 +18,12 @@
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.
+ + 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
+ when there were only a handful of tasks.
------ old releases ------------------------------
diff --git a/html/task.html b/html/task.html
index f3f309b08..1ed9df5e0 100644
--- a/html/task.html
+++ b/html/task.html
@@ -112,7 +112,12 @@
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.
+
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
+ when there were only a handful of tasks.
From d69d6585311b4e2703401196c3e91a437aa73f55 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Tue, 3 Mar 2009 17:15:40 -0500
Subject: [PATCH 046/103] Unit Tests - tag
- Added unit tests to test the +tag and -tag task modification
feature.
---
src/tests/tag.t | 74 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 74 insertions(+)
create mode 100755 src/tests/tag.t
diff --git a/src/tests/tag.t b/src/tests/tag.t
new file mode 100755
index 000000000..ceeb24dea
--- /dev/null
+++ b/src/tests/tag.t
@@ -0,0 +1,74 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 9;
+
+# Create the rc file.
+if (open my $fh, '>', 'tag.rc')
+{
+ print $fh "data.location=.\n";
+ close $fh;
+ ok (-r 'tag.rc', 'Created tag.rc');
+}
+
+# Add task with tags.
+my $output = qx{../task rc:tag.rc add +1 This +2 is a test +3; ../task rc:tag.rc info 1};
+#like ($output, qr/^Tags\s+1 2 3$/ms, 'tags found');
+like ($output, qr/^Tags\s+1 2 3\n/m, 'tags found');
+
+# Remove tags.
+$output = qx{../task rc:tag.rc 1 -3 -2 -1; ../task rc:tag.rc info 1};
+unlike ($output, qr/^Tags/m, '-3 -2 -1 tag removed');
+
+# Add tags.
+$output = qx{../task rc:tag.rc 1 +4 +5 +6; ../task rc:tag.rc info 1};
+like ($output, qr/^Tags\s+4 5 6\n/m, 'tags found');
+
+# Remove tags.
+$output = qx{../task rc:tag.rc 1 -4 -5 -6; ../task rc:tag.rc info 1};
+unlike ($output, qr/^Tags/m, '-4 -5 -6 tag removed');
+
+# Add and remove tags.
+$output = qx{../task rc:tag.rc 1 +duplicate -duplicate; ../task rc:tag.rc info 1};
+unlike ($output, qr/^Tags/m, '+duplicate -duplicate NOP');
+
+# Remove missing tag.
+$output = qx{../task rc:tag.rc 1 -missing; ../task rc:tag.rc info 1};
+unlike ($output, qr/^Tags/m, '-missing NOP');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pendind.data', 'Removed pending.data');
+
+unlink 'tag.rc';
+ok (!-r 'tag.rc', 'Removed tag.rc');
+
+exit 0;
+
From d7a9d06360b4aba2bfe580e9f4065a4d4f815375 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Tue, 3 Mar 2009 21:19:07 -0500
Subject: [PATCH 047/103] Unit Tests - add, bug_hang, bug_period, bug_sort,
nag, tag
- Implemented unit tests to verify tag manipulation
- Implemented unit tests to verify nag functionality
- Implemented unit tests to verify bug fix for hang on shadow write
- Implemented unit tests to verify bug fix for unsupported recurrence periods
- Implemented unit tests to verify bug fix for hang on sort
- Corrected typo in add.t
---
src/tests/add.t | 2 +-
src/tests/bug_hang.t | 83 +++++++++++++++++++++
src/tests/bug_period.t | 164 +++++++++++++++++++++++++++++++++++++++++
src/tests/bug_sort.t | 2 +-
src/tests/nag.t | 2 +-
src/tests/tag.t | 3 +-
6 files changed, 251 insertions(+), 5 deletions(-)
create mode 100755 src/tests/bug_hang.t
create mode 100755 src/tests/bug_period.t
diff --git a/src/tests/add.t b/src/tests/add.t
index 26a82f0ee..db6f5c553 100755
--- a/src/tests/add.t
+++ b/src/tests/add.t
@@ -63,7 +63,7 @@ like ($output, qr/Status\s+Pending\n/, 'add Pending');
# Cleanup.
unlink 'pending.data';
-ok (!-r 'pendind.data', 'Removed pending.data');
+ok (!-r 'pending.data', 'Removed pending.data');
unlink 'add.rc';
ok (!-r 'add.rc', 'Removed add.rc');
diff --git a/src/tests/bug_hang.t b/src/tests/bug_hang.t
new file mode 100755
index 000000000..dbe229919
--- /dev/null
+++ b/src/tests/bug_hang.t
@@ -0,0 +1,83 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 5;
+
+# Create the rc file.
+if (open my $fh, '>', 'hang.rc')
+{
+ print $fh "data.location=.\n",
+ "shadow.file=shadow.txt\n",
+ "shadow.command=list\n";
+ close $fh;
+ ok (-r 'hang.rc', 'Created hang.rc');
+}
+
+=pod
+I found a bug in the current version of task. Using recur and a shadow file will
+lead to an infinite loop. To reproduce it, define a shadow file in the .taskrc,
+set a command for it that rebuilds the database, e.g. "list", and then add a
+task with a recurrence set, e.g. "task add due:today recur:1d infinite loop".
+Task will then loop forever and add the same recurring task until it runs out of
+memory. So I checked the source and I believe I found the cause.
+handleRecurrence() in task.cpp will modify the mask, but writes it only after it
+has added all new tasks. Adding the task will, however, invoke onChangeCallback,
+which starts the same process all over again.
+=cut
+
+eval
+{
+ $SIG{'ALRM'} = sub {die "alarm\n"};
+ alarm 10;
+ my $output = qx{../task rc:hang.rc list;
+ ../task rc:hang.rc add due:today recur:1d infinite loop;
+ ../task rc:hang.rc info 1};
+ alarm 0;
+
+ like ($output, qr/^Description\s+infinite loop\n/m, 'no hang');
+};
+
+if ($@ eq "alarm\n")
+{
+ fail ('task hang on add or recurring task, with shadow file, for 10s');
+}
+
+# Cleanup.
+unlink 'shadow.txt';
+ok (!-r 'shadow.txt', 'Removed shadow.txt');
+
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'hang.rc';
+ok (!-r 'hang.rc', 'Removed hang.rc');
+
+exit 0;
+
diff --git a/src/tests/bug_period.t b/src/tests/bug_period.t
new file mode 100755
index 000000000..dff6888ff
--- /dev/null
+++ b/src/tests/bug_period.t
@@ -0,0 +1,164 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 41;
+
+# Create the rc file.
+if (open my $fh, '>', 'period.rc')
+{
+ print $fh "data.location=.\n";
+ close $fh;
+ ok (-r 'period.rc', 'Created period.rc');
+}
+
+=pod
+http://github.com/pbeckingham/task/blob/857f813a24f7ce15fea9f2c28aadad84cb5c8847/src/task.cpp
+619 // If the period is an 'easy' one, add it to current, and we're done.
+620 int days = convertDuration (period);
+
+Date getNextRecurrence (Date& current, std::string& period)
+
+starting at line 509 special cases several possibilities for period, '\d\s?m'
+'monthly', 'quarterly', 'semiannual', 'bimonthly', 'biannual', 'biyearly'.
+Everything else falls through with period being passed to convertDuration.
+convertDuration doesn't know about 'daily' though so it seems to be returning 0.
+
+Confirmed:
+ getNextRecurrence convertDuration
+ ----------------- ---------------
+ daily
+ day
+ weekly
+ sennight
+ biweekly
+ fortnight
+ monthly monthly
+ quarterly quarterly
+ semiannual semiannual
+ bimonthly bimonthly
+ biannual biannual
+ biyearly biyearly
+ annual
+ yearly
+ *m *m
+ *q *q
+ *d
+ *w
+ *y
+=cut
+
+my $output = qx{../task rc:period.rc add daily due:tomorrow recur:daily};
+like ($output, qr/^$/, 'recur:daily');
+
+$output = qx{../task rc:period.rc add day due:tomorrow recur:day};
+like ($output, qr/^$/, 'recur:day');
+
+$output = qx{../task rc:period.rc add weekly due:tomorrow recur:weekly};
+like ($output, qr/^$/, 'recur:weekly');
+
+$output = qx{../task rc:period.rc add sennight due:tomorrow recur:sennight};
+like ($output, qr/^$/, 'recur:sennight');
+
+$output = qx{../task rc:period.rc add biweekly due:tomorrow recur:biweekly};
+like ($output, qr/^$/, 'recur:biweekly');
+
+$output = qx{../task rc:period.rc add fortnight due:tomorrow recur:fortnight};
+like ($output, qr/^$/, 'recur:fortnight');
+
+$output = qx{../task rc:period.rc add monthly due:tomorrow recur:monthly};
+like ($output, qr/^$/, 'recur:monthly');
+
+$output = qx{../task rc:period.rc add quarterly due:tomorrow recur:quarterly};
+like ($output, qr/^$/, 'recur:quarterly');
+
+$output = qx{../task rc:period.rc add semiannual due:tomorrow recur:semiannual};
+like ($output, qr/^$/, 'recur:semiannual');
+
+$output = qx{../task rc:period.rc add bimonthly due:tomorrow recur:bimonthly};
+like ($output, qr/^$/, 'recur:bimonthly');
+
+$output = qx{../task rc:period.rc add biannual due:tomorrow recur:biannual};
+like ($output, qr/^$/, 'recur:biannual');
+
+$output = qx{../task rc:period.rc add biyearly due:tomorrow recur:biyearly};
+like ($output, qr/^$/, 'recur:biyearly');
+
+$output = qx{../task rc:period.rc add annual due:tomorrow recur:annual};
+like ($output, qr/^$/, 'recur:annual');
+
+$output = qx{../task rc:period.rc add yearly due:tomorrow recur:yearly};
+like ($output, qr/^$/, 'recur:yearly');
+
+$output = qx{../task rc:period.rc add 2d due:tomorrow recur:2d};
+like ($output, qr/^$/, 'recur:2m');
+
+$output = qx{../task rc:period.rc add 2w due:tomorrow recur:2w};
+like ($output, qr/^$/, 'recur:2q');
+
+$output = qx{../task rc:period.rc add 2m due:tomorrow recur:2m};
+like ($output, qr/^$/, 'recur:2d');
+
+$output = qx{../task rc:period.rc add 2q due:tomorrow recur:2q};
+like ($output, qr/^$/, 'recur:2w');
+
+$output = qx{../task rc:period.rc add 2y due:tomorrow recur:2y};
+like ($output, qr/^$/, 'recur:2y');
+
+# Verify that the recurring task instances get created. One of each.
+$output = qx{../task rc:period.rc list};
+like ($output, qr/\bdaily\b/, 'verify daily');
+like ($output, qr/\bday\b/, 'verify day');
+like ($output, qr/\bweekly\b/, 'verify weekly');
+like ($output, qr/\bsennight\b/, 'verify sennight');
+like ($output, qr/\bbiweekly\b/, 'verify biweekly');
+like ($output, qr/\bfortnight\b/, 'verify fortnight');
+like ($output, qr/\bmonthly\b/, 'verify monthly');
+like ($output, qr/\bquarterly\b/, 'verify quarterly');
+like ($output, qr/\bsemiannual\b/, 'verify semiannual');
+like ($output, qr/\bbimonthly\b/, 'verify bimonthly');
+like ($output, qr/\bbiannual\b/, 'verify biannual');
+like ($output, qr/\bbiyearly\b/, 'verify biyearly');
+like ($output, qr/\bannual\b/, 'verify annual');
+like ($output, qr/\byearly\b/, 'verify yearly');
+like ($output, qr/\b2d\b/, 'verify 2d');
+like ($output, qr/\b2w\b/, 'verify 2w');
+like ($output, qr/\b2m\b/, 'verify 2m');
+like ($output, qr/\b2q\b/, 'verify 2q');
+like ($output, qr/\b2y\b/, 'verify 2y');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'period.rc';
+ok (!-r 'period.rc', 'Removed period.rc');
+
+exit 0;
+
diff --git a/src/tests/bug_sort.t b/src/tests/bug_sort.t
index 4b9c4973a..0d0d49eac 100755
--- a/src/tests/bug_sort.t
+++ b/src/tests/bug_sort.t
@@ -53,7 +53,7 @@ like ($output, qr/three.*one.*two/msi, 'list did not hang after pri:H on 1');
# Cleanup.
unlink 'pending.data';
-ok (!-r 'pendind.data', 'Removed pending.data');
+ok (!-r 'pending.data', 'Removed pending.data');
unlink 'bug_sort.rc';
ok (!-r 'bug_sort.rc', 'Removed bug_sort.rc');
diff --git a/src/tests/nag.t b/src/tests/nag.t
index d9dc94d76..d55aac456 100755
--- a/src/tests/nag.t
+++ b/src/tests/nag.t
@@ -56,7 +56,7 @@ ok (qx{../task rc:nag.rc do 1} !~ qr/NAG/, 'do due:yesterday -> no nag');
# Cleanup.
unlink 'pending.data';
-ok (!-r 'pendind.data', 'Removed pending.data');
+ok (!-r 'pending.data', 'Removed pending.data');
unlink 'nag.rc';
ok (!-r 'nag.rc', 'Removed nag.rc');
diff --git a/src/tests/tag.t b/src/tests/tag.t
index ceeb24dea..f55ba0dbf 100755
--- a/src/tests/tag.t
+++ b/src/tests/tag.t
@@ -40,7 +40,6 @@ if (open my $fh, '>', 'tag.rc')
# Add task with tags.
my $output = qx{../task rc:tag.rc add +1 This +2 is a test +3; ../task rc:tag.rc info 1};
-#like ($output, qr/^Tags\s+1 2 3$/ms, 'tags found');
like ($output, qr/^Tags\s+1 2 3\n/m, 'tags found');
# Remove tags.
@@ -65,7 +64,7 @@ unlike ($output, qr/^Tags/m, '-missing NOP');
# Cleanup.
unlink 'pending.data';
-ok (!-r 'pendind.data', 'Removed pending.data');
+ok (!-r 'pending.data', 'Removed pending.data');
unlink 'tag.rc';
ok (!-r 'tag.rc', 'Removed tag.rc');
From d831ab335a2bc44c52ca81d2798e3e4088be497b Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Tue, 3 Mar 2009 23:13:31 -0500
Subject: [PATCH 048/103] Report Column Header
- Added "Number" to the ghistory graph title.
---
src/report.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/report.cpp b/src/report.cpp
index a43d50706..f1e806fde 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -1070,7 +1070,7 @@ std::string handleReportGHistory (TDB& tdb, T& task, Config& conf)
table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
table.addColumn ("Year");
table.addColumn ("Month");
- table.addColumn ("Added/Completed/Deleted");
+ table.addColumn ("Number Added/Completed/Deleted");
if (conf.get ("color", true))
{
From d573599a7e1e2bed945b51067220a7f8607520c8 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Wed, 4 Mar 2009 00:04:09 -0500
Subject: [PATCH 049/103] Unit Tests - subproject
- Implemented unit test to verify that the project and subproject
filtering is working properly.
---
src/tests/subproject.t | 73 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 73 insertions(+)
create mode 100755 src/tests/subproject.t
diff --git a/src/tests/subproject.t b/src/tests/subproject.t
new file mode 100755
index 000000000..04703a28a
--- /dev/null
+++ b/src/tests/subproject.t
@@ -0,0 +1,73 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 11;
+
+# Create the rc file.
+if (open my $fh, '>', 'sp.rc')
+{
+ print $fh "data.location=.\n";
+ close $fh;
+ ok (-r 'sp.rc', 'Created sp.rc');
+}
+
+my $setup = "../task rc:sp.rc add project:abc abc;"
+ . "../task rc:sp.rc add project:ab ab;"
+ . "../task rc:sp.rc add project:a a;"
+ . "../task rc:sp.rc add project:b b;";
+qx{$setup};
+
+my $output = qx{../task rc:sp.rc list project:b};
+like ($output, qr/\bb\s*$/m, 'abc,ab,a,b | b -> b');
+
+$output = qx{../task rc:sp.rc list project:a};
+like ($output, qr/\babc\s*$/m, 'abc,ab,a,b | a -> abc');
+like ($output, qr/\bab\s*$/m, 'abc,ab,a,b | a -> ab');
+like ($output, qr/\ba\s*$/m, 'abc,ab,a,b | a -> a');
+
+$output = qx{../task rc:sp.rc list project:ab};
+like ($output, qr/\babc\s*$/m, 'abc,ab,a,b | a -> abc');
+like ($output, qr/\bab\s*$/m, 'abc,ab,a,b | a -> ab');
+
+$output = qx{../task rc:sp.rc list project:abc};
+like ($output, qr/\babc\s*$/m, 'abc,ab,a,b | a -> abc');
+
+$output = qx{../task rc:sp.rc list project:abcd};
+like ($output, qr/^No matches.$/, 'abc,ab,a,b | abcd -> nul');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'sp.rc';
+ok (!-r 'sp.rc', 'Removed sp.rc');
+
+exit 0;
+
From 9988ecec5efce4eecc5bccc34fa0343f79b82bfd Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Wed, 4 Mar 2009 09:37:00 -0500
Subject: [PATCH 050/103] Portability
- Modified util.cpp to allow clean compilation on Solaris.
---
src/util.cpp | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/src/util.cpp b/src/util.cpp
index fd73c3b39..bc1bea9f2 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -29,10 +29,12 @@
#include
#include
#include
+#include
#include
#include
#include
#include
+#include
#include "Date.h"
#include "Table.h"
#include "task.h"
@@ -335,20 +337,20 @@ std::string expandPath (const std::string& in)
#ifdef SOLARIS
int flock (int fd, int operation)
{
- struct flock flock;
+ struct flock fl;
switch (operation & ~LOCK_NB)
{
case LOCK_SH:
- flock.l_type = F_RDLCK;
+ fl.l_type = F_RDLCK;
break;
case LOCK_EX:
- flock.l_type = F_WRLCK;
+ fl.l_type = F_WRLCK;
break;
case LOCK_UN:
- flock.l_type = F_UNLCK;
+ fl.l_type = F_UNLCK;
break;
default:
@@ -356,11 +358,11 @@ int flock (int fd, int operation)
return -1;
}
- flock.l_whence = 0;
- flock.l_start = 0;
- flock.l_len = 0;
+ fl.l_whence = 0;
+ fl.l_start = 0;
+ fl.l_len = 0;
- return fcntl (fd, (operation & LOCK_NB) ? F_SETLK : F_SETLKW, &flock);
+ return fcntl (fd, (operation & LOCK_NB) ? F_SETLK : F_SETLKW, &fl);
}
#endif
From 9535121c1ef2e8ee2568546715aaa55feae15bdc Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Thu, 5 Mar 2009 10:08:25 -0500
Subject: [PATCH 051/103] Performance
- Removed the unnecessary sort in the 'completed' report. The tasks
are already sorted.
---
src/report.cpp | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/report.cpp b/src/report.cpp
index f1e806fde..d2bb6e1e2 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -189,7 +189,10 @@ std::string handleCompleted (TDB& tdb, T& task, Config& conf)
table.setColumnJustification (1, Table::left);
table.setColumnJustification (2, Table::left);
- table.sortOn (0, Table::ascendingDate);
+ // Note: There is deliberately no sorting. The original sorting was on the
+ // end date. Tasks are appended to completed.data naturally sorted by
+ // the end date, so that sequence is assumed to remain unchanged, and
+ // relied upon here.
// Iterate over each task, and apply selection criteria.
for (unsigned int i = 0; i < tasks.size (); ++i)
From 41b8b207d4f23141a565635956e69a26fea98eaf Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Thu, 5 Mar 2009 10:13:10 -0500
Subject: [PATCH 052/103] Documentation Update
- Added examples to the grammar file.
- Added recent change to ChangeLog, html/task.html.
---
ChangeLog | 1 +
grammar.bnf | 7 ++++++-
html/task.html | 1 +
3 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/ChangeLog b/ChangeLog
index e85e949a0..9ec97dcbb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -24,6 +24,7 @@
and shadow files.
+ Fixed bug with the task sort alogrithm, which led to an unstable sequence
when there were only a handful of tasks.
+ + Performance enhanced by eliminating unnecessary sorting.
------ old releases ------------------------------
diff --git a/grammar.bnf b/grammar.bnf
index ba82df08e..2905420f4 100644
--- a/grammar.bnf
+++ b/grammar.bnf
@@ -1,7 +1,12 @@
# This is a full BNF grammar for the task command line. It is intended that a
# future release of task will incorporate a complete lexer/parser implementing
-# this grammar.
+# this grammar, which will allow for more sophisticated command lines, for
+# example:
+#
+# task delete 1 2 4-7
+# task add pri:H pro:X -- pro pri 1 ///
+#
command ::= simple_command
| filter_command filter?
diff --git a/html/task.html b/html/task.html
index 1ed9df5e0..81cae7bf0 100644
--- a/html/task.html
+++ b/html/task.html
@@ -118,6 +118,7 @@
and shadow files.
Fixed bug with the task sort alogrithm, which led to an unstable sequence
when there were only a handful of tasks.
+
Performance enhanced by eliminating unnecessary sorting.
From 463c968cacb46597e68d04a5d583680257f45f75 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Fri, 6 Mar 2009 00:39:28 -0500
Subject: [PATCH 053/103] Unit Tests - undo.t
- Added unit tests for the undo command, which verify that a task may
only be undone if a TDB::gc has not occurred.
---
src/tests/undo.t | 74 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 74 insertions(+)
create mode 100755 src/tests/undo.t
diff --git a/src/tests/undo.t b/src/tests/undo.t
new file mode 100755
index 000000000..ec023b31d
--- /dev/null
+++ b/src/tests/undo.t
@@ -0,0 +1,74 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 15;
+
+# Create the rc file.
+if (open my $fh, '>', 'undo.rc')
+{
+ print $fh "data.location=.\n";
+ close $fh;
+ ok (-r 'undo.rc', 'Created undo.rc');
+}
+
+# Test the add/do/undo commands.
+my $output = qx{../task rc:undo.rc add one; ../task rc:undo.rc info 1};
+ok (-r 'pending.data', 'pending.data created');
+like ($output, qr/Status\s+Pending\n/, 'Pending');
+
+$output = qx{../task rc:undo.rc do 1; ../task rc:undo.rc info 1};
+ok (! -r 'completed.data', 'completed.data not created');
+like ($output, qr/Status\s+Completed\n/, 'Completed');
+
+$output = qx{../task rc:undo.rc undo 1; ../task rc:undo.rc info 1};
+ok (! -r 'completed.data', 'completed.data not created');
+like ($output, qr/Status\s+Pending\n/, 'Pending');
+
+$output = qx{../task rc:undo.rc do 1; ../task rc:undo.rc list};
+like ($output, qr/^No matches/, 'No matches');
+
+$output = qx{../task rc:undo.rc undo 1; ../task rc:undo.rc info 1};
+like ($output, qr/Task 1 not found/, 'task not found');
+like ($output, qr/reliably undone/, 'can only be reliable undone...');
+
+# Cleanup.
+ok (-r 'pending.data', 'Need to remove pending.data');
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+ok (-r 'completed.data', 'Need to remove completed.data');
+unlink 'completed.data';
+ok (!-r 'completed.data', 'Removed completed.data');
+
+unlink 'undo.rc';
+ok (!-r 'undo.rc', 'Removed undo.rc');
+
+exit 0;
+
From 3b1d396e0a3ea005df1c18ef7de89f20fa35459d Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Fri, 6 Mar 2009 21:59:25 -0500
Subject: [PATCH 054/103] Acknowledgement
- Michael Greb acknowledged for his help in reporting several bugs in
sufficient detail, and narrowing down the cause.
---
AUTHORS | 1 +
1 file changed, 1 insertion(+)
diff --git a/AUTHORS b/AUTHORS
index 9fae397e7..7fcc9c14b 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -6,6 +6,7 @@ Contributing Authors:
Andy Lester
H. İbrahim Güngör
Stefan Dorn
+ Michael Greb
With thanks to:
Eugene Kramer
From 6a7c66aa05feca13f8c1e66939bb7f563613fd3d Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sat, 7 Mar 2009 00:14:58 -0500
Subject: [PATCH 055/103] Unit Tests - color.disable color.pri config.obsolete
- Added unit tests to cover automatic colorization by priority.
- Added unit tests to cover automatic disabling of color when !isatty.
- Added unit tests to cover display of unsupported configuration
variable in the 'version' report.
- Added support the '_forcecolor' configuration variable to allow the
possibility of unit tests that test color support, yet redirect
output to a file. This configuration variable will not be
documented.
---
src/Config.cpp | 7 ++-
src/command.cpp | 19 +++++--
src/report.cpp | 54 +++++++++----------
src/task.cpp | 4 +-
src/tests/{bug_hang.t => bug.hang.t} | 0
src/tests/{bug_period.t => bug.period.t} | 0
src/tests/{bug_sort.t => bug.sort.t} | 0
src/tests/color.disable.t | 58 +++++++++++++++++++++
src/tests/color.pri.t | 66 ++++++++++++++++++++++++
src/tests/config.obsolete.t | 57 ++++++++++++++++++++
10 files changed, 231 insertions(+), 34 deletions(-)
rename src/tests/{bug_hang.t => bug.hang.t} (100%)
rename src/tests/{bug_period.t => bug.period.t} (100%)
rename src/tests/{bug_sort.t => bug.sort.t} (100%)
create mode 100755 src/tests/color.disable.t
create mode 100755 src/tests/color.pri.t
create mode 100755 src/tests/config.obsolete.t
diff --git a/src/Config.cpp b/src/Config.cpp
index fee5cf39a..64e07b04c 100644
--- a/src/Config.cpp
+++ b/src/Config.cpp
@@ -36,9 +36,14 @@
#include "Config.h"
////////////////////////////////////////////////////////////////////////////////
+// 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.
+// 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 ()
{
- // These are default (but overridable) reports.
(*this)["report.long.columns"] = "id,project,priority,entry,start,due,age,tags,description";
(*this)["report.long.sort"] = "due+,priority-,project+";
(*this)["report.list.columns"] = "id,project,priority,due,active,age,description";
diff --git a/src/command.cpp b/src/command.cpp
index 9bd940fb2..03e6e473d 100644
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -113,7 +113,7 @@ std::string handleProjects (TDB& tdb, T& task, Config& conf)
table.addColumn ("Project");
table.addColumn ("Tasks");
- if (conf.get ("color", true))
+ if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
{
table.setColumnUnderline (0);
table.setColumnUnderline (1);
@@ -316,7 +316,7 @@ std::string handleVersion (Config& conf)
table.addColumn ("Config variable");
table.addColumn ("Value");
- if (conf.get ("color", true))
+ if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
{
table.setColumnUnderline (0);
table.setColumnUnderline (1);
@@ -345,9 +345,13 @@ std::string handleVersion (Config& conf)
out << "Copyright (C) 2006 - 2009, P. Beckingham."
<< std::endl
- << (conf.get ("color", true) ? Text::colorize (Text::bold, Text::nocolor, PACKAGE) : PACKAGE)
+ << ((conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
+ ? Text::colorize (Text::bold, Text::nocolor, PACKAGE)
+ : PACKAGE)
<< " "
- << (conf.get ("color", true) ? Text::colorize (Text::bold, Text::nocolor, VERSION) : VERSION)
+ << ((conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
+ ? Text::colorize (Text::bold, Text::nocolor, VERSION)
+ : VERSION)
<< std::endl
<< disclaimer.render ()
<< std::endl
@@ -364,6 +368,11 @@ std::string handleVersion (Config& conf)
"monthsperline nag newest next oldest 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
+ // is redirected to a file, or stdout is not a tty.
+ recognized += " _forcecolor";
+
std::vector unrecognized;
foreach (i, all)
{
@@ -696,7 +705,7 @@ std::string handleColor (Config& conf)
{
std::stringstream out;
- if (conf.get ("color", true))
+ if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
{
out << optionalBlankLine (conf) << "Foreground" << std::endl
<< " "
diff --git a/src/report.cpp b/src/report.cpp
index d2bb6e1e2..afa460821 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -172,7 +172,7 @@ std::string handleCompleted (TDB& tdb, T& task, Config& conf)
table.addColumn ("Project");
table.addColumn ("Description");
- if (conf.get ("color", true))
+ if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
{
table.setColumnUnderline (0);
table.setColumnUnderline (1);
@@ -209,7 +209,7 @@ std::string handleCompleted (TDB& tdb, T& task, Config& conf)
table.addCell (row, 1, refTask.getAttribute ("project"));
table.addCell (row, 2, refTask.getDescription ());
- if (conf.get ("color", true))
+ 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"));
@@ -261,7 +261,7 @@ std::string handleInfo (TDB& tdb, T& task, Config& conf)
table.addColumn ("Name");
table.addColumn ("Value");
- if (conf.get ("color", true))
+ if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
{
table.setColumnUnderline (0);
table.setColumnUnderline (1);
@@ -359,7 +359,7 @@ std::string handleInfo (TDB& tdb, T& task, Config& conf)
Date nextweek = now + 7 * 86400;
imminent = dt < nextweek ? true : false;
- if (conf.get ("color", true))
+ if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
{
if (overdue)
table.setCellFg (row, 1, Text::colorCode (conf.get ("color.overdue", "red")));
@@ -513,7 +513,7 @@ std::string handleReportSummary (TDB& tdb, T& task, Config& conf)
table.addColumn ("Complete");
table.addColumn ("0% 100%");
- if (conf.get ("color", true))
+ if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
{
table.setColumnUnderline (0);
table.setColumnUnderline (1);
@@ -550,7 +550,7 @@ std::string handleReportSummary (TDB& tdb, T& task, Config& conf)
int completedBar = (c * barWidth) / (c + p);
std::string bar;
- if (conf.get ("color", true))
+ if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
{
bar = "\033[42m";
for (int b = 0; b < completedBar; ++b)
@@ -654,7 +654,7 @@ std::string handleReportNext (TDB& tdb, T& task, Config& conf)
table.addColumn ("Age");
table.addColumn ("Description");
- if (conf.get ("color", true))
+ if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
{
table.setColumnUnderline (0);
table.setColumnUnderline (1);
@@ -729,7 +729,7 @@ std::string handleReportNext (TDB& tdb, T& task, Config& conf)
table.addCell (row, 5, age);
table.addCell (row, 6, refTask.getDescription ());
- if (conf.get ("color", true))
+ 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"));
@@ -879,7 +879,7 @@ std::string handleReportHistory (TDB& tdb, T& task, Config& conf)
table.addColumn ("Deleted");
table.addColumn ("Net");
- if (conf.get ("color", true))
+ if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
{
table.setColumnUnderline (0);
table.setColumnUnderline (1);
@@ -942,7 +942,7 @@ std::string handleReportHistory (TDB& tdb, T& task, Config& conf)
}
table.addCell (row, 5, net);
- if (conf.get ("color", true) && net)
+ if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false) && net)
table.setCellFg (row, 5, net > 0 ? Text::red: Text::green);
}
@@ -952,7 +952,7 @@ std::string handleReportHistory (TDB& tdb, T& task, Config& conf)
row = table.addRow ();
table.addCell (row, 1, "Average");
- if (conf.get ("color", true)) table.setRowFg (row, Text::bold);
+ if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false)) table.setRowFg (row, Text::bold);
table.addCell (row, 2, totalAdded / (table.rowCount () - 2));
table.addCell (row, 3, totalCompleted / (table.rowCount () - 2));
table.addCell (row, 4, totalDeleted / (table.rowCount () - 2));
@@ -1075,7 +1075,7 @@ std::string handleReportGHistory (TDB& tdb, T& task, Config& conf)
table.addColumn ("Month");
table.addColumn ("Number Added/Completed/Deleted");
- if (conf.get ("color", true))
+ if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
{
table.setColumnUnderline (0);
table.setColumnUnderline (1);
@@ -1131,7 +1131,7 @@ std::string handleReportGHistory (TDB& tdb, T& task, Config& conf)
unsigned int deletedBar = (widthOfBar * deletedGroup[i->first]) / maxLine;
std::string bar = "";
- if (conf.get ("color", true))
+ if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
{
char number[24];
std::string aBar = "";
@@ -1190,7 +1190,7 @@ std::string handleReportGHistory (TDB& tdb, T& task, Config& conf)
<< table.render ()
<< std::endl;
- if (conf.get ("color", true))
+ if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
out << "Legend: "
<< Text::colorize (Text::black, Text::on_red, "added")
<< ", "
@@ -1232,7 +1232,7 @@ std::string renderMonths (
table.addColumn ("Fr");
table.addColumn ("Sa");
- if (conf.get ("color", true))
+ if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
{
table.setColumnUnderline (i + 1);
table.setColumnUnderline (i + 2);
@@ -1302,7 +1302,7 @@ std::string renderMonths (
table.addCell (row, thisCol, d);
- if (conf.get ("color", true) &&
+ if ((conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false)) &&
today.day () == d &&
today.month () == months.at (c) &&
today.year () == years.at (c))
@@ -1313,7 +1313,7 @@ std::string renderMonths (
{
Date due (::atoi (it->getAttribute ("due").c_str ()));
- if (conf.get ("color", true) &&
+ if ((conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false)) &&
due.day () == d &&
due.month () == months.at (c) &&
due.year () == years.at (c))
@@ -1455,7 +1455,7 @@ std::string handleReportActive (TDB& tdb, T& task, Config& conf)
table.addColumn ("Due");
table.addColumn ("Description");
- if (conf.get ("color", true))
+ if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
{
table.setColumnUnderline (0);
table.setColumnUnderline (1);
@@ -1511,7 +1511,7 @@ std::string handleReportActive (TDB& tdb, T& task, Config& conf)
table.addCell (row, 3, due);
table.addCell (row, 4, refTask.getDescription ());
- if (conf.get ("color", true))
+ 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"));
@@ -1576,7 +1576,7 @@ std::string handleReportOverdue (TDB& tdb, T& task, Config& conf)
table.addColumn ("Due");
table.addColumn ("Description");
- if (conf.get ("color", true))
+ if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
{
table.setColumnUnderline (0);
table.setColumnUnderline (1);
@@ -1625,7 +1625,7 @@ std::string handleReportOverdue (TDB& tdb, T& task, Config& conf)
table.addCell (row, 3, due);
table.addCell (row, 4, refTask.getDescription ());
- if (conf.get ("color", true))
+ 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"));
@@ -1693,7 +1693,7 @@ std::string handleReportOldest (TDB& tdb, T& task, Config& conf)
table.addColumn ("Age");
table.addColumn ("Description");
- if (conf.get ("color", true))
+ if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
{
table.setColumnUnderline (0);
table.setColumnUnderline (1);
@@ -1769,7 +1769,7 @@ std::string handleReportOldest (TDB& tdb, T& task, Config& conf)
table.addCell (row, 5, age);
table.addCell (row, 6, refTask.getDescription ());
- if (conf.get ("color", true))
+ 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"));
@@ -1840,7 +1840,7 @@ std::string handleReportNewest (TDB& tdb, T& task, Config& conf)
table.addColumn ("Age");
table.addColumn ("Description");
- if (conf.get ("color", true))
+ if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
{
table.setColumnUnderline (0);
table.setColumnUnderline (1);
@@ -1917,7 +1917,7 @@ std::string handleReportNewest (TDB& tdb, T& task, Config& conf)
table.addCell (row, 5, age);
table.addCell (row, 6, refTask.getDescription ());
- if (conf.get ("color", true))
+ 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"));
@@ -2449,7 +2449,7 @@ std::string handleCustomReport (
// Common to all columns.
// Add underline.
- if (conf.get (std::string ("color"), true))
+ if (conf.get (std::string ("color"), true) || conf.get (std::string ("_forcecolor"), false))
table.setColumnUnderline (columnCount);
else
table.setTableDashedUnderline ();
@@ -2514,7 +2514,7 @@ std::string handleCustomReport (
}
}
- if (conf.get ("color", true))
+ if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
{
Text::color fg = Text::colorCode (tasks[row].getAttribute ("fg"));
Text::color bg = Text::colorCode (tasks[row].getAttribute ("bg"));
diff --git a/src/task.cpp b/src/task.cpp
index 727db1f16..04c73c3e6 100644
--- a/src/task.cpp
+++ b/src/task.cpp
@@ -290,7 +290,9 @@ int main (int argc, char** argv)
if (!isatty (fileno (stdout)))
{
conf.set ("curses", "off");
- conf.set ("color", "off");
+
+ if (! conf.get (std::string ("_forcecolor"), false))
+ conf.set ("color", "off");
}
TDB tdb;
diff --git a/src/tests/bug_hang.t b/src/tests/bug.hang.t
similarity index 100%
rename from src/tests/bug_hang.t
rename to src/tests/bug.hang.t
diff --git a/src/tests/bug_period.t b/src/tests/bug.period.t
similarity index 100%
rename from src/tests/bug_period.t
rename to src/tests/bug.period.t
diff --git a/src/tests/bug_sort.t b/src/tests/bug.sort.t
similarity index 100%
rename from src/tests/bug_sort.t
rename to src/tests/bug.sort.t
diff --git a/src/tests/color.disable.t b/src/tests/color.disable.t
new file mode 100755
index 000000000..c4a0f4a58
--- /dev/null
+++ b/src/tests/color.disable.t
@@ -0,0 +1,58 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 6;
+
+# Create the rc file.
+if (open my $fh, '>', 'color.rc')
+{
+ print $fh "data.location=.\n",
+ "color.pri.H=red\n";
+ close $fh;
+ ok (-r 'color.rc', 'Created color.rc');
+}
+
+# Test the add command.
+qx{../task rc:color.rc add priority:H red};
+my $output = qx{../task rc:color.rc list};
+
+like ($output, qr/red/, 'color.disable - found red');
+unlike ($output, qr/\033\[31m/, 'color.disable - no color red');
+unlike ($output, qr/\033\[0m/, 'color.disable - no color reset');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'color.rc';
+ok (!-r 'color.rc', 'Removed color.rc');
+
+exit 0;
+
diff --git a/src/tests/color.pri.t b/src/tests/color.pri.t
new file mode 100755
index 000000000..14a2ee42d
--- /dev/null
+++ b/src/tests/color.pri.t
@@ -0,0 +1,66 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 7;
+
+# Create the rc file.
+if (open my $fh, '>', 'color.rc')
+{
+ print $fh "data.location=.\n",
+ "color.pri.H=red\n",
+ "color.pri.M=green\n",
+ "color.pri.L=blue\n",
+ "color.pri.none=yellow\n",
+ "_forcecolor=1\n";
+ close $fh;
+ ok (-r 'color.rc', 'Created color.rc');
+}
+
+# Test the add command.
+qx{../task rc:color.rc add priority:H red};
+qx{../task rc:color.rc add priority:M green};
+qx{../task rc:color.rc add priority:L blue};
+qx{../task rc:color.rc add yellow};
+my $output = qx{../task rc:color.rc list};
+
+like ($output, qr/ \033\[31m .* red .* \033\[0m /x, 'color.pri.H');
+like ($output, qr/ \033\[32m .* green .* \033\[0m /x, 'color.pri.M');
+like ($output, qr/ \033\[34m .* blue .* \033\[0m /x, 'color.pri.L');
+like ($output, qr/ \033\[33m .* yellow .* \033\[0m /x, 'color.pri.none');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'color.rc';
+ok (!-r 'color.rc', 'Removed color.rc');
+
+exit 0;
+
diff --git a/src/tests/config.obsolete.t b/src/tests/config.obsolete.t
new file mode 100755
index 000000000..7a5f34bc1
--- /dev/null
+++ b/src/tests/config.obsolete.t
@@ -0,0 +1,57 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 5;
+
+# Create the rc file.
+if (open my $fh, '>', 'obsolete.rc')
+{
+ print $fh "data.location=.\n",
+ "foo=1\n";
+ close $fh;
+ ok (-r 'obsolete.rc', 'Created obsolete.rc');
+}
+
+# Test the add command.
+my $output = qx{../task rc:obsolete.rc version};
+
+like ($output, qr/Your .taskrc file contains these unrecognized variables:\n/,
+ 'unsupported configuration variable');
+like ($output, qr/ foo\n/, 'unsupported configuration variable');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'obsolete.rc';
+ok (!-r 'obsolete.rc', 'Removed obsolete.rc');
+
+exit 0;
+
From 3088e1ebe1f9624b1f303e2d8f5db1114d532944 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sat, 7 Mar 2009 02:06:13 -0500
Subject: [PATCH 056/103] Unit Tests - abbreviation, filter, benchmark
- Added tests for attribute abbreviation.
- Added tests for filter permutation testing.
- Added benchmark for ongoing performance measurement.
- Mentioned test suite in docs. Why not?
---
ChangeLog | 2 +
html/task.html | 2 +
src/tests/abbreviation.t | 77 ++++++++++++++++
src/tests/benchmark.t | 96 +++++++++++++++++++
src/tests/filter.t | 193 +++++++++++++++++++++++++++++++++++++++
5 files changed, 370 insertions(+)
create mode 100755 src/tests/abbreviation.t
create mode 100755 src/tests/benchmark.t
create mode 100755 src/tests/filter.t
diff --git a/ChangeLog b/ChangeLog
index 9ec97dcbb..4ab22d837 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -25,6 +25,8 @@
+ Fixed bug with the task sort alogrithm, 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
+ to help ensure higher quality releases.
------ old releases ------------------------------
diff --git a/html/task.html b/html/task.html
index 81cae7bf0..a65a68a96 100644
--- a/html/task.html
+++ b/html/task.html
@@ -119,6 +119,8 @@
Fixed bug with the task sort alogrithm, 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
+ to help ensure higher quality releases.
diff --git a/src/tests/abbreviation.t b/src/tests/abbreviation.t
new file mode 100755
index 000000000..4d9b27515
--- /dev/null
+++ b/src/tests/abbreviation.t
@@ -0,0 +1,77 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 15;
+
+# Create the rc file.
+if (open my $fh, '>', 'abbrev.rc')
+{
+ print $fh "data.location=.\n";
+ close $fh;
+ ok (-r 'abbrev.rc', 'Created abbrev.rc');
+}
+
+# Test the add command.
+qx{../task rc:abbrev.rc add priority:H with};
+qx{../task rc:abbrev.rc add without};
+
+my $output = qx{../task rc:abbrev.rc list priority:H};
+like ($output, qr/\bwith\b/, 'priority:H with');
+unlike ($output, qr/\bwithout\b/, 'priority:H without');
+
+$output = qx{../task rc:abbrev.rc list priorit:H};
+like ($output, qr/\bwith\b/, 'priorit:H with');
+unlike ($output, qr/\bwithout\b/, 'priorit:H without');
+
+$output = qx{../task rc:abbrev.rc list priori:H};
+like ($output, qr/\bwith\b/, 'priori:H with');
+unlike ($output, qr/\bwithout\b/, 'priori:H without');
+
+$output = qx{../task rc:abbrev.rc list prior:H};
+like ($output, qr/\bwith\b/, 'prior:H with');
+unlike ($output, qr/\bwithout\b/, 'prior:H without');
+
+$output = qx{../task rc:abbrev.rc list prio:H};
+like ($output, qr/\bwith\b/, 'prio:H with');
+unlike ($output, qr/\bwithout\b/, 'prio:H without');
+
+$output = qx{../task rc:abbrev.rc list pri:H};
+like ($output, qr/\bwith\b/, 'pri:H with');
+unlike ($output, qr/\bwithout\b/, 'pri:H without');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'abbrev.rc';
+ok (!-r 'abbrev.rc', 'Removed abbrev.rc');
+
+exit 0;
+
diff --git a/src/tests/benchmark.t b/src/tests/benchmark.t
new file mode 100755
index 000000000..dd069deb4
--- /dev/null
+++ b/src/tests/benchmark.t
@@ -0,0 +1,96 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 4;
+
+# Create the rc file.
+if (open my $fh, '>', 'bench.rc')
+{
+ print $fh "data.location=.\n",
+ "_forcecolor=1\n";
+ close $fh;
+ ok (-r 'bench.rc', 'Created bench.rc');
+}
+
+# Do lots of things. Time it all.
+
+my @tags = qw(t_one t_two t_three t_four t_five t_six t_seven t_eight);
+my @projects = qw(p_one p_two p_three p_foud p_five p_six p_seven p_eight);
+my @priorities = qw(H M L);
+my $description = 'This is a medium-sized description with no special characters';
+
+# Start the clock.
+my $start = time ();
+diag ("start=$start");
+
+# Make a mess.
+for my $i (1 .. 1000)
+{
+ my $project = $projects[rand % 8];
+ my $priority = $priorities[rand % 3];
+ my $tag = $tags[rand % 8];
+
+ qx{../task rc:bench.rc add project:$project priority:$priority +$tag $i $description};
+}
+diag ("1000 tasks added");
+
+qx{../task rc:bench.rc /with/WITH/} for 1 .. 200;
+qx{../task rc:bench.rc done $_} for 201 .. 400;
+qx{../task rc:bench.rc start $_} for 401 .. 600;
+diag ("600 tasks altered");
+
+# Report it all.
+qx{../task rc:bench.rc ls};
+qx{../task rc:bench.rc list};
+qx{../task rc:bench.rc list priority:H};
+qx{../task rc:bench.rc list +tag};
+qx{../task rc:bench.rc list project_A};
+qx{../task rc:bench.rc long};
+qx{../task rc:bench.rc completed};
+qx{../task rc:bench.rc history};
+qx{../task rc:bench.rc ghistory};
+
+# Stop the clock.
+my $stop = time ();
+diag ("stop=$stop");
+diag ("total=" . ($stop - $start));
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'completed.data';
+ok (!-r 'completed.data', 'Removed completed.data');
+
+unlink 'bench.rc';
+ok (!-r 'bench.rc', 'Removed bench.rc');
+
+exit 0;
+
diff --git a/src/tests/filter.t b/src/tests/filter.t
new file mode 100755
index 000000000..5fd4e918b
--- /dev/null
+++ b/src/tests/filter.t
@@ -0,0 +1,193 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 108;
+
+# Create the rc file.
+if (open my $fh, '>', 'filter.rc')
+{
+ print $fh "data.location=.\n";
+ close $fh;
+ ok (-r 'filter.rc', 'Created filter.rc');
+}
+
+# Test the filters.
+qx{../task rc:filter.rc add project:A priority:H +tag one foo};
+qx{../task rc:filter.rc add project:A priority:H two};
+qx{../task rc:filter.rc add project:A three};
+qx{../task rc:filter.rc add priority:H four};
+qx{../task rc:filter.rc add +tag five};
+qx{../task rc:filter.rc add six foo};
+qx{../task rc:filter.rc add priority:L seven bar foo};
+
+my $output = qx{../task rc:filter.rc list};
+like ($output, qr/one/, 'a1');
+like ($output, qr/two/, 'a2');
+like ($output, qr/three/, 'a3');
+like ($output, qr/four/, 'a4');
+like ($output, qr/five/, 'a5');
+like ($output, qr/six/, 'a6');
+like ($output, qr/seven/, 'a7');
+
+$output = qx{../task rc:filter.rc list project:A};
+like ($output, qr/one/, 'b1');
+like ($output, qr/two/, 'b2');
+like ($output, qr/three/, 'b3');
+unlike ($output, qr/four/, 'b4');
+unlike ($output, qr/five/, 'b5');
+unlike ($output, qr/six/, 'b6');
+unlike ($output, qr/seven/, 'b7');
+
+$output = qx{../task rc:filter.rc list priority:H};
+like ($output, qr/one/, 'c1');
+like ($output, qr/two/, 'c2');
+unlike ($output, qr/three/, 'c3');
+like ($output, qr/four/, 'c4');
+unlike ($output, qr/five/, 'c5');
+unlike ($output, qr/six/, 'c6');
+unlike ($output, qr/seven/, 'c7');
+
+$output = qx{../task rc:filter.rc list priority:};
+unlike ($output, qr/one/, 'd1');
+unlike ($output, qr/two/, 'd2');
+like ($output, qr/three/, 'd3');
+unlike ($output, qr/four/, 'd4');
+like ($output, qr/five/, 'd5');
+like ($output, qr/six/, 'd6');
+unlike ($output, qr/seven/, 'd7');
+
+$output = qx{../task rc:filter.rc list foo};
+like ($output, qr/one/, 'e1');
+unlike ($output, qr/two/, 'e2');
+unlike ($output, qr/three/, 'e3');
+unlike ($output, qr/four/, 'e4');
+unlike ($output, qr/five/, 'e5');
+like ($output, qr/six/, 'e6');
+like ($output, qr/seven/, 'e7');
+
+$output = qx{../task rc:filter.rc list foo bar};
+unlike ($output, qr/one/, 'f1');
+unlike ($output, qr/two/, 'f2');
+unlike ($output, qr/three/, 'f3');
+unlike ($output, qr/four/, 'f4');
+unlike ($output, qr/five/, 'f5');
+unlike ($output, qr/six/, 'f6');
+like ($output, qr/seven/, 'f7');
+
+$output = qx{../task rc:filter.rc list +tag};
+like ($output, qr/one/, 'g1');
+unlike ($output, qr/two/, 'g2');
+unlike ($output, qr/three/, 'g3');
+unlike ($output, qr/four/, 'g4');
+like ($output, qr/five/, 'g5');
+unlike ($output, qr/six/, 'g6');
+unlike ($output, qr/seven/, 'g7');
+
+$output = qx{../task rc:filter.rc list project:A priority:H};
+like ($output, qr/one/, 'h1');
+like ($output, qr/two/, 'h2');
+unlike ($output, qr/three/, 'h3');
+unlike ($output, qr/four/, 'h4');
+unlike ($output, qr/five/, 'h5');
+unlike ($output, qr/six/, 'h6');
+unlike ($output, qr/seven/, 'h7');
+
+$output = qx{../task rc:filter.rc list project:A priority:};
+unlike ($output, qr/one/, 'i1');
+unlike ($output, qr/two/, 'i2');
+like ($output, qr/three/, 'i3');
+unlike ($output, qr/four/, 'i4');
+unlike ($output, qr/five/, 'i5');
+unlike ($output, qr/six/, 'i6');
+unlike ($output, qr/seven/, 'i7');
+
+$output = qx{../task rc:filter.rc list project:A foo};
+like ($output, qr/one/, 'j1');
+unlike ($output, qr/two/, 'j2');
+unlike ($output, qr/three/, 'j3');
+unlike ($output, qr/four/, 'j4');
+unlike ($output, qr/five/, 'j5');
+unlike ($output, qr/six/, 'j6');
+unlike ($output, qr/seven/, 'j7');
+
+$output = qx{../task rc:filter.rc list project:A +tag};
+like ($output, qr/one/, 'k1');
+unlike ($output, qr/two/, 'k2');
+unlike ($output, qr/three/, 'k3');
+unlike ($output, qr/four/, 'k4');
+unlike ($output, qr/five/, 'k5');
+unlike ($output, qr/six/, 'k6');
+unlike ($output, qr/seven/, 'k7');
+
+$output = qx{../task rc:filter.rc list project:A priority:H foo};
+like ($output, qr/one/, 'l1');
+unlike ($output, qr/two/, 'l2');
+unlike ($output, qr/three/, 'l3');
+unlike ($output, qr/four/, 'l4');
+unlike ($output, qr/five/, 'l5');
+unlike ($output, qr/six/, 'l6');
+unlike ($output, qr/seven/, 'l7');
+
+$output = qx{../task rc:filter.rc list project:A priority:H +tag};
+like ($output, qr/one/, 'm1');
+unlike ($output, qr/two/, 'm2');
+unlike ($output, qr/three/, 'm3');
+unlike ($output, qr/four/, 'm4');
+unlike ($output, qr/five/, 'm5');
+unlike ($output, qr/six/, 'm6');
+unlike ($output, qr/seven/, 'm7');
+
+$output = qx{../task rc:filter.rc list project:A priority:H foo +tag};
+like ($output, qr/one/, 'n1');
+unlike ($output, qr/two/, 'n2');
+unlike ($output, qr/three/, 'n3');
+unlike ($output, qr/four/, 'n4');
+unlike ($output, qr/five/, 'n5');
+unlike ($output, qr/six/, 'n6');
+unlike ($output, qr/seven/, 'n7');
+
+$output = qx{../task rc:filter.rc list project:A priority:H foo +tag baz};
+unlike ($output, qr/one/, 'n1');
+unlike ($output, qr/two/, 'n2');
+unlike ($output, qr/three/, 'n3');
+unlike ($output, qr/four/, 'n4');
+unlike ($output, qr/five/, 'n5');
+unlike ($output, qr/six/, 'n6');
+unlike ($output, qr/seven/, 'n7');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'filter.rc';
+ok (!-r 'filter.rc', 'Removed filter.rc');
+
+exit 0;
+
From 4fa4c5f532313ea0d7b853fb8e09b3741b6b3113 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sun, 8 Mar 2009 17:59:27 -0400
Subject: [PATCH 057/103] Unit Tests - t.benchmark.t
- Added benchmark to measure time taken to parse 1,000,000 T records.
---
configure.ac | 12 +++----
src/T.cpp | 2 +-
src/tests/.gitignore | 3 +-
src/tests/Makefile | 5 ++-
src/tests/t.benchmark.t.cpp | 69 +++++++++++++++++++++++++++++++++++++
5 files changed, 80 insertions(+), 11 deletions(-)
create mode 100644 src/tests/t.benchmark.t.cpp
diff --git a/configure.ac b/configure.ac
index d6e95db0f..4ae1d6760 100644
--- a/configure.ac
+++ b/configure.ac
@@ -14,14 +14,12 @@ debug_default="yes"
AC_ARG_ENABLE(debug, [ --enable-debug=[no/yes] turn on debugging
[default=$debug_default]],, enable_debug=$debug_default)
# Yes, shell scripts can be used
-if test "x$enable_debug" = "xyes"; then
-CFLAGS="$CFLAGS -Wall -pedantic -ggdb3 -DDEBUG"
-CXXFLAGS="$CFLAGS -Wall -pedantic -ggdb3 -DDEBUG"
-AC_MSG_RESULT(yes)
+if test "$enable_debug" = "yes"; then
+ CXXFLAGS="$CFLAGS -Wall -pedantic -ggdb3 -DDEBUG"
+ AC_MSG_RESULT(yes)
else
-CFLAGS="$CFLAGS -O3"
-CXXFLAGS="$CFLAGS -O3"
-AC_MSG_RESULT(no)
+ CXXFLAGS="$CFLAGS -O3"
+ AC_MSG_RESULT(no)
fi
# Check for OS.
diff --git a/src/T.cpp b/src/T.cpp
index a21b31638..61acd52f4 100644
--- a/src/T.cpp
+++ b/src/T.cpp
@@ -468,7 +468,7 @@ void T::parse (const std::string& line)
break;
default:
- throw std::string ();
+ throw std::string ("Unrecognized task file format.");
break;
}
}
diff --git a/src/tests/.gitignore b/src/tests/.gitignore
index 1445bb223..94ab5cd82 100644
--- a/src/tests/.gitignore
+++ b/src/tests/.gitignore
@@ -1,7 +1,6 @@
t.t
+t.benchmark.t
tdb.t
date.t
duration.t
-pending.data
-completed.data
diff --git a/src/tests/Makefile b/src/tests/Makefile
index c6c3ac3d8..b98b58bd4 100644
--- a/src/tests/Makefile
+++ b/src/tests/Makefile
@@ -1,4 +1,4 @@
-PROJECT = t.t tdb.t date.t duration.t
+PROJECT = t.t tdb.t date.t duration.t t.benchmark.t
CFLAGS = -I. -I.. -Wall -pedantic -ggdb3 -fno-rtti
LFLAGS = -L/usr/local/lib
OBJECTS = ../TDB.o ../T.o ../parse.o ../text.o ../Date.o ../util.o ../Config.o
@@ -29,3 +29,6 @@ date.t: date.t.o $(OBJECTS) test.o
duration.t: duration.t.o $(OBJECTS) test.o
g++ duration.t.o $(OBJECTS) test.o $(LFLAGS) -o duration.t
+t.benchmark.t: t.benchmark.t.o $(OBJECTS) test.o
+ g++ t.benchmark.t.o $(OBJECTS) test.o $(LFLAGS) -o t.benchmark.t
+
diff --git a/src/tests/t.benchmark.t.cpp b/src/tests/t.benchmark.t.cpp
new file mode 100644
index 000000000..9adf4d578
--- /dev/null
+++ b/src/tests/t.benchmark.t.cpp
@@ -0,0 +1,69 @@
+////////////////////////////////////////////////////////////////////////////////
+// task - a command line task list manager.
+//
+// Copyright 2006 - 2009, Paul Beckingham.
+// All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; either version 2 of the License, or (at your option) any later
+// version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+// details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the
+//
+// Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor,
+// Boston, MA
+// 02110-1301
+// USA
+//
+////////////////////////////////////////////////////////////////////////////////
+#include
+#include "../T.h"
+#include "../task.h"
+#include "test.h"
+
+////////////////////////////////////////////////////////////////////////////////
+int main (int argc, char** argv)
+{
+ UnitTest test (1);
+
+ std::string sample = "d346065c-7ef6-49af-ae77-19c1825807f5 "
+ "- "
+ "[bug performance solaris linux osx] "
+ "[due:1236142800 entry:1236177552 priority:H project:task-1.5.0 start:1236231761] "
+ "Profile task and identify performance bottlenecks";
+
+ // Start clock
+ test.diag ("start");
+ struct timeval start;
+ gettimeofday (&start, NULL);
+
+ for (int i = 0; i < 1000000; i++)
+ {
+ T t (sample);
+ }
+
+ // End clock
+ struct timeval end;
+ gettimeofday (&end, NULL);
+ test.diag ("end");
+
+ int diff = ((end.tv_sec * 1000000) + end.tv_usec) -
+ ((start.tv_sec * 1000000) + start.tv_usec);
+
+ char s[16];
+ sprintf (s, "%d.%06d", diff/1000000, diff%1000000);
+ test.pass (std::string ("1,000,000 T::parse calls in ") + s + "s");
+
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
From 0362b41f3b7ae97f77ab91ec0f4e5133bd8d0715 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sun, 8 Mar 2009 20:49:33 -0400
Subject: [PATCH 058/103] Performance
- Added Timer class to display high resolution timing information.
- Found terrible bug in Table::optimize that was taking up 99.7%,
on average, of the Table::rendering time, including sorting. This
fix naturally causes a 187-fold speedup of rendering.
- Changed report.cpp in handleCustomReport to only load pending tasks,
instead of all pending tasks. Subtle, but important difference.
---
.gitignore | 1 -
ChangeLog | 1 +
Makefile.in | 595 ++++++++++++++++++++++++++++++++++++++++++
html/task.html | 1 +
src/Makefile.am | 2 +-
src/Makefile.in | 10 +-
src/Table.cpp | 40 ++-
src/Timer.cpp | 56 ++++
src/Timer.h | 46 ++++
src/report.cpp | 2 +-
src/tests/benchmark.t | 31 ++-
11 files changed, 765 insertions(+), 20 deletions(-)
create mode 100644 Makefile.in
create mode 100644 src/Timer.cpp
create mode 100644 src/Timer.h
diff --git a/.gitignore b/.gitignore
index c61760acc..3fb778785 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,3 @@
-Makefile.in
aclocal.m4
autom4te.cache
auto.h*
diff --git a/ChangeLog b/ChangeLog
index 4ab22d837..1b41b79b0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -27,6 +27,7 @@
+ Performance enhanced by eliminating unnecessary sorting.
+ Task now has a large (and growing) test suite and bug regression tests
to help ensure higher quality releases.
+ + Fixed bug that caused performance hit during table rendering.
------ old releases ------------------------------
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 000000000..4e4244870
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,595 @@
+# Makefile.in generated by automake 1.10 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+subdir = .
+DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(srcdir)/auto.h.in \
+ $(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \
+ depcomp install-sh missing
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = auto.h
+CONFIG_CLEAN_FILES =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-dvi-recursive install-exec-recursive \
+ install-html-recursive install-info-recursive \
+ install-pdf-recursive install-ps-recursive install-recursive \
+ installcheck-recursive installdirs-recursive pdf-recursive \
+ ps-recursive uninstall-recursive
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+ { test ! -d $(distdir) \
+ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
+ && rm -fr $(distdir); }; }
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+distuninstallcheck_listfiles = find . -type f -print
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build_alias = @build_alias@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host_alias = @host_alias@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = src
+EXTRA_DIST = DEVELOPERS
+all: auto.h
+ $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+am--refresh:
+ @:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \
+ cd $(srcdir) && $(AUTOMAKE) --gnu \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ echo ' $(SHELL) ./config.status'; \
+ $(SHELL) ./config.status;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+
+auto.h: stamp-h1
+ @if test ! -f $@; then \
+ rm -f stamp-h1; \
+ $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
+ else :; fi
+
+stamp-h1: $(srcdir)/auto.h.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status auto.h
+$(srcdir)/auto.h.in: $(am__configure_deps)
+ cd $(top_srcdir) && $(AUTOHEADER)
+ rm -f stamp-h1
+ touch $@
+
+distclean-hdr:
+ -rm -f auto.h stamp-h1
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) auto.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) auto.h.in $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) auto.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) auto.h.in $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ $(am__remove_distdir)
+ test -d $(distdir) || mkdir $(distdir)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+ list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ distdir=`$(am__cd) $(distdir) && pwd`; \
+ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+ (cd $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$top_distdir" \
+ distdir="$$distdir/$$subdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+ -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
+ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+ || chmod -R a+r $(distdir)
+dist-gzip: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__remove_distdir)
+
+dist-bzip2: distdir
+ tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
+ $(am__remove_distdir)
+
+dist-tarZ: distdir
+ tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+ $(am__remove_distdir)
+
+dist-shar: distdir
+ shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+ $(am__remove_distdir)
+
+dist-zip: distdir
+ -rm -f $(distdir).zip
+ zip -rq $(distdir).zip $(distdir)
+ $(am__remove_distdir)
+
+dist dist-all: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ case '$(DIST_ARCHIVES)' in \
+ *.tar.gz*) \
+ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
+ *.tar.bz2*) \
+ bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
+ *.tar.Z*) \
+ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+ *.shar.gz*) \
+ GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
+ *.zip*) \
+ unzip $(distdir).zip ;;\
+ esac
+ chmod -R a-w $(distdir); chmod a+w $(distdir)
+ mkdir $(distdir)/_build
+ mkdir $(distdir)/_inst
+ chmod a-w $(distdir)
+ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+ && cd $(distdir)/_build \
+ && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+ $(DISTCHECK_CONFIGURE_FLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+ distuninstallcheck \
+ && chmod -R a-w "$$dc_install_base" \
+ && ({ \
+ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+ } || { rm -rf "$$dc_destdir"; exit 1; }) \
+ && rm -rf "$$dc_destdir" \
+ && $(MAKE) $(AM_MAKEFLAGS) dist \
+ && rm -rf $(DIST_ARCHIVES) \
+ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck
+ $(am__remove_distdir)
+ @(echo "$(distdir) archives ready for distribution: "; \
+ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+ @cd $(distuninstallcheck_dir) \
+ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
+ || { echo "ERROR: files left after uninstall:" ; \
+ if test -n "$(DESTDIR)"; then \
+ echo " (check DESTDIR support)"; \
+ fi ; \
+ $(distuninstallcheck_listfiles) ; \
+ exit 1; } >&2
+distcleancheck: distclean
+ @if test '$(srcdir)' = . ; then \
+ echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+ exit 1 ; \
+ fi
+ @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left in build directory after distclean:" ; \
+ $(distcleancheck_listfiles) ; \
+ exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile auto.h
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-hdr distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-info: install-info-recursive
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-ps: install-ps-recursive
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf $(top_srcdir)/autom4te.cache
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \
+ install-strip
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+ all all-am am--refresh check check-am clean clean-generic \
+ ctags ctags-recursive dist dist-all dist-bzip2 dist-gzip \
+ dist-shar dist-tarZ dist-zip distcheck distclean \
+ distclean-generic distclean-hdr distclean-tags distcleancheck \
+ distdir distuninstallcheck dvi dvi-am html html-am info \
+ info-am install install-am install-data install-data-am \
+ install-dvi install-dvi-am install-exec install-exec-am \
+ install-html install-html-am install-info install-info-am \
+ install-man install-pdf install-pdf-am install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
+ pdf-am ps ps-am tags tags-recursive uninstall uninstall-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/html/task.html b/html/task.html
index a65a68a96..64b8cba47 100644
--- a/html/task.html
+++ b/html/task.html
@@ -121,6 +121,7 @@
Performance enhanced by eliminating unnecessary sorting.
Task now has a large (and growing) test suite and bug regression tests
to help ensure higher quality releases.
+
Fixed bug that caused performance hit during table rendering.
diff --git a/src/Makefile.am b/src/Makefile.am
index 2e92854a2..8203dbb14 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,2 +1,2 @@
bin_PROGRAMS = task
-task_SOURCES = Config.cpp Date.cpp T.cpp TDB.cpp Table.cpp Grid.cpp color.cpp parse.cpp task.cpp command.cpp report.cpp util.cpp text.cpp rules.cpp Config.h Date.h T.h TDB.h Table.h Grid.h color.h task.h
+task_SOURCES = Config.cpp Date.cpp T.cpp TDB.cpp Table.cpp Grid.cpp Timer.cpp color.cpp parse.cpp task.cpp command.cpp report.cpp util.cpp text.cpp rules.cpp Config.h Date.h T.h TDB.h Table.h Grid.h Timer.h color.h task.h
diff --git a/src/Makefile.in b/src/Makefile.in
index c8ca21f5f..ae8c519e5 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -44,9 +44,10 @@ am__installdirs = "$(DESTDIR)$(bindir)"
binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
PROGRAMS = $(bin_PROGRAMS)
am_task_OBJECTS = Config.$(OBJEXT) Date.$(OBJEXT) T.$(OBJEXT) \
- TDB.$(OBJEXT) Table.$(OBJEXT) Grid.$(OBJEXT) color.$(OBJEXT) \
- parse.$(OBJEXT) task.$(OBJEXT) command.$(OBJEXT) \
- report.$(OBJEXT) util.$(OBJEXT) text.$(OBJEXT) rules.$(OBJEXT)
+ TDB.$(OBJEXT) Table.$(OBJEXT) Grid.$(OBJEXT) Timer.$(OBJEXT) \
+ color.$(OBJEXT) parse.$(OBJEXT) task.$(OBJEXT) \
+ command.$(OBJEXT) report.$(OBJEXT) util.$(OBJEXT) \
+ text.$(OBJEXT) rules.$(OBJEXT)
task_OBJECTS = $(am_task_OBJECTS)
task_LDADD = $(LDADD)
DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@
@@ -154,7 +155,7 @@ sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
-task_SOURCES = Config.cpp Date.cpp T.cpp TDB.cpp Table.cpp Grid.cpp color.cpp parse.cpp task.cpp command.cpp report.cpp util.cpp text.cpp rules.cpp Config.h Date.h T.h TDB.h Table.h Grid.h color.h task.h
+task_SOURCES = Config.cpp Date.cpp T.cpp TDB.cpp Table.cpp Grid.cpp Timer.cpp color.cpp parse.cpp task.cpp command.cpp report.cpp util.cpp text.cpp rules.cpp Config.h Date.h T.h TDB.h Table.h Grid.h Timer.h color.h task.h
all: all-am
.SUFFIXES:
@@ -227,6 +228,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/T.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TDB.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Table.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Timer.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/color.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/command.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Po@am__quote@
diff --git a/src/Table.cpp b/src/Table.cpp
index 2bf97be2b..26ed0bacb 100644
--- a/src/Table.cpp
+++ b/src/Table.cpp
@@ -749,12 +749,50 @@ void Table::optimize (std::string& output)
*/
// \s\n -> \n
+/*
+ Well, how about that!
+
+ The benchmark.t unit test adds a 1000 tasks, fiddles with some of them, then
+ runs a series of reports. The results are timed, and look like this:
+
+ 1000 tasks added in 3 seconds
+ 600 tasks altered in 32 seconds
+ 'task ls' in 26 seconds
+ 'task list' in 17 seconds
+ 'task list pri:H' in 19 seconds
+ 'task list +tag' in 0 seconds
+ 'task list project_A' in 0 seconds
+ 'task long' in 29 seconds
+ 'task completed' in 2 seconds
+ 'task history' in 0 seconds
+ 'task ghistory' in 0 seconds
+
+ This performance is terrible. To identify the worst offender, Various Timer
+ objects were added in Table::render, assuming that table sorting is the major
+ bottleneck. But no, it is Table::optimize that is the problem. After
+ commenting out the code below, the results are now:
+
+ 1000 tasks added in 3 seconds
+ 600 tasks altered in 29 seconds
+ 'task ls' in 0 seconds
+ 'task list' in 0 seconds
+ 'task list pri:H' in 1 seconds
+ 'task list +tag' in 0 seconds
+ 'task list project_A' in 0 seconds
+ 'task long' in 0 seconds
+ 'task completed' in 0 seconds
+ 'task history' in 0 seconds
+ 'task ghistory' in 0 seconds
+
+ Much better. Table::optimize is currently disabled.
+
size_t i = 0;
while ((i = output.find (" \n")) != std::string::npos)
{
output = output.substr (0, i) +
- output.substr (i + 1, std::string::npos);
+ output.substr (i + 2, std::string::npos);
}
+*/
/*
std::cout << int ((100 * (start - output.length ()) / start))
diff --git a/src/Timer.cpp b/src/Timer.cpp
new file mode 100644
index 000000000..cbd9f1dc7
--- /dev/null
+++ b/src/Timer.cpp
@@ -0,0 +1,56 @@
+////////////////////////////////////////////////////////////////////////////////
+// task - a command line task list manager.
+//
+// Copyright 2006 - 2009, Paul Beckingham.
+// All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; either version 2 of the License, or (at your option) any later
+// version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+// details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the
+//
+// Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor,
+// Boston, MA
+// 02110-1301
+// USA
+//
+////////////////////////////////////////////////////////////////////////////////
+#include
+#include
+#include
+
+////////////////////////////////////////////////////////////////////////////////
+// Timer starts when the object is constructed.
+Timer::Timer (const std::string& description)
+: mDescription (description)
+{
+ ::gettimeofday (&mStart, NULL);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Timer stops when the object is desctructed.
+Timer::~Timer ()
+{
+ struct timeval end;
+ ::gettimeofday (&end, NULL);
+
+ std::cout << "Timer "
+ << mDescription
+ << " "
+ << std::setprecision (6)
+ << ((end.tv_sec - mStart.tv_sec) +
+ ((end.tv_usec - mStart.tv_usec ) / 1000000.0))
+ << std::endl;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
diff --git a/src/Timer.h b/src/Timer.h
new file mode 100644
index 000000000..6b561aac2
--- /dev/null
+++ b/src/Timer.h
@@ -0,0 +1,46 @@
+////////////////////////////////////////////////////////////////////////////////
+// task - a command line task list manager.
+//
+// Copyright 2006 - 2009, Paul Beckingham.
+// All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free Software
+// Foundation; either version 2 of the License, or (at your option) any later
+// version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+// details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the
+//
+// Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor,
+// Boston, MA
+// 02110-1301
+// USA
+//
+////////////////////////////////////////////////////////////////////////////////
+#ifndef INCLUDED_TIMER
+#define INCLUDED_TIMER
+
+#include
+#include
+
+class Timer
+{
+public:
+ Timer (const std::string&);
+ ~Timer ();
+
+private:
+ std::string mDescription;
+ struct timeval mStart;
+};
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
diff --git a/src/report.cpp b/src/report.cpp
index afa460821..a762a5c69 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -2262,7 +2262,7 @@ std::string handleCustomReport (
// Load all pending tasks.
std::vector tasks;
- tdb.allPendingT (tasks);
+ tdb.pendingT (tasks);
handleRecurrence (tdb, tasks);
// Apply filters.
diff --git a/src/tests/benchmark.t b/src/tests/benchmark.t
index dd069deb4..73088a4a0 100755
--- a/src/tests/benchmark.t
+++ b/src/tests/benchmark.t
@@ -48,6 +48,7 @@ my $description = 'This is a medium-sized description with no special characters
# Start the clock.
my $start = time ();
+my $cursor = $start;
diag ("start=$start");
# Make a mess.
@@ -59,23 +60,29 @@ for my $i (1 .. 1000)
qx{../task rc:bench.rc add project:$project priority:$priority +$tag $i $description};
}
-diag ("1000 tasks added");
+diag ("1000 tasks added in " . (time () - $cursor) . " seconds");
+$cursor = time ();
qx{../task rc:bench.rc /with/WITH/} for 1 .. 200;
qx{../task rc:bench.rc done $_} for 201 .. 400;
qx{../task rc:bench.rc start $_} for 401 .. 600;
-diag ("600 tasks altered");
+diag ("600 tasks altered in " . (time () - $cursor) . " seconds");
+$cursor = time ();
-# Report it all.
-qx{../task rc:bench.rc ls};
-qx{../task rc:bench.rc list};
-qx{../task rc:bench.rc list priority:H};
-qx{../task rc:bench.rc list +tag};
-qx{../task rc:bench.rc list project_A};
-qx{../task rc:bench.rc long};
-qx{../task rc:bench.rc completed};
-qx{../task rc:bench.rc history};
-qx{../task rc:bench.rc ghistory};
+# Report it all. Note that all Timer information is displayed.
+
+for (1 .. 100)
+{
+ diag (grep {/^Timer /} qx{../task rc:bench.rc ls});
+ diag (grep {/^Timer /} qx{../task rc:bench.rc list});
+ diag (grep {/^Timer /} qx{../task rc:bench.rc list priority:H});
+ diag (grep {/^Timer /} qx{../task rc:bench.rc list +tag});
+ diag (grep {/^Timer /} qx{../task rc:bench.rc list project_A});
+ diag (grep {/^Timer /} qx{../task rc:bench.rc long});
+ diag (grep {/^Timer /} qx{../task rc:bench.rc completed});
+ diag (grep {/^Timer /} qx{../task rc:bench.rc history});
+ diag (grep {/^Timer /} qx{../task rc:bench.rc ghistory});
+}
# Stop the clock.
my $stop = time ();
From 3f418c6fdc8e833c5d83a4e1d3d5975347246f13 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sun, 8 Mar 2009 21:29:55 -0400
Subject: [PATCH 059/103] Performance
- Made Table::optimize a public method.
- Table::optimize called only from handleReportGHistory, where it's
needed.
- Retaining benchmark.txt, to allow further improvements.
---
src/Table.cpp | 26 +++++++++++++++++++++-----
src/Table.h | 2 +-
src/report.cpp | 6 +++++-
src/tests/benchmark.txt | 40 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 67 insertions(+), 7 deletions(-)
create mode 100644 src/tests/benchmark.txt
diff --git a/src/Table.cpp b/src/Table.cpp
index 26ed0bacb..cce934cfe 100644
--- a/src/Table.cpp
+++ b/src/Table.cpp
@@ -742,7 +742,7 @@ int Table::columnCount ()
// ^[[31mName^[[0m ^[[31mValue^[[0m -> ^[[31mName Value^[[0m
//
// This method is a work in progress.
-void Table::optimize (std::string& output)
+void Table::optimize (std::string& output) const
{
/*
int start = output.length ();
@@ -785,14 +785,32 @@ void Table::optimize (std::string& output)
'task ghistory' in 0 seconds
Much better. Table::optimize is currently disabled.
+*/
size_t i = 0;
- while ((i = output.find (" \n")) != std::string::npos)
+ while ((i = output.find (" \n")) != std::string::npos)
+ {
+ output = output.substr (0, i) +
+ output.substr (i + 8, std::string::npos);
+ }
+
+ while ((i = output.find (" \n")) != std::string::npos)
+ {
+ output = output.substr (0, i) +
+ output.substr (i + 4, std::string::npos);
+ }
+
+ while ((i = output.find (" \n")) != std::string::npos)
{
output = output.substr (0, i) +
output.substr (i + 2, std::string::npos);
}
-*/
+
+ while ((i = output.find (" \n")) != std::string::npos)
+ {
+ output = output.substr (0, i) +
+ output.substr (i + 1, std::string::npos);
+ }
/*
std::cout << int ((100 * (start - output.length ()) / start))
@@ -1066,8 +1084,6 @@ const std::string Table::render ()
output += "\n";
}
- // Eliminate redundant color codes.
- optimize (output);
return output;
}
diff --git a/src/Table.h b/src/Table.h
index e1d244e14..765c1116a 100644
--- a/src/Table.h
+++ b/src/Table.h
@@ -85,6 +85,7 @@ public:
int rowCount ();
int columnCount ();
const std::string render ();
+ void optimize (std::string&) const;
private:
std::string getCell (const int, const int);
@@ -101,7 +102,6 @@ private:
const std::string formatHeader (const int, const int, const int);
const std::string formatHeaderDashedUnderline (const int, const int, const int);
void formatCell (const int, const int, const int, const int, std::vector &, std::string&);
- void optimize (std::string&);
void sort (std::vector &);
void clean (std::string&);
diff --git a/src/report.cpp b/src/report.cpp
index a762a5c69..f6aa675ca 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -1205,7 +1205,11 @@ std::string handleReportGHistory (TDB& tdb, T& task, Config& conf)
else
out << "No tasks." << std::endl;
- return out.str ();
+ // Eliminate redundant color codes.
+ std::string optimized = out.str ();
+ table.optimize (optimized);
+
+ return optimized;
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/src/tests/benchmark.txt b/src/tests/benchmark.txt
new file mode 100644
index 000000000..78cfba505
--- /dev/null
+++ b/src/tests/benchmark.txt
@@ -0,0 +1,40 @@
+3/8/2009
+ Before:
+ Table::render
+ 26.1792
+ 16.67
+ 18.9697
+ 28.6328
+ 1.86553
+ 0.00044
+ 0.000319
+ ---------
+ 92.317989
+
+ After Table::optimize removed:
+ Table::render
+ 0.146177
+ 0.145928
+ 0.184444
+ 0.014784
+ 0.000512
+ 0.000267
+ ---------
+ 0.492112
+
+ Speedup:
+ 92.317989 / 0.492112 = 187.6
+
+3/8/2009
+ New benchmark:
+ 1..4
+ ok 1 - Created bench.rc
+ # start=1236558734
+ # 1000 tasks added in 3 seconds
+ # 600 tasks altered in 29 seconds
+ # stop=1236558924
+ # total=190
+ ok 2 - Removed pending.data
+ ok 3 - Removed completed.data
+ ok 4 - Removed bench.rc
+
From 28e997691ff72033c4e1ff94cc90eefc38252d24 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sun, 8 Mar 2009 22:56:47 -0400
Subject: [PATCH 060/103] Unit Tests - repair
- Added auto right trim to all table rows, which is a much more
efficient way of doing what Table::optimize was doing.
- Table::optimize is now a nop.
---
src/Table.cpp | 48 ++++++++++-------------------------------
src/Table.h | 2 +-
src/report.cpp | 8 ++-----
src/tests/benchmark.txt | 8 +++----
src/tests/bug.sort.t | 1 -
5 files changed, 18 insertions(+), 49 deletions(-)
diff --git a/src/Table.cpp b/src/Table.cpp
index cce934cfe..fc0ff1296 100644
--- a/src/Table.cpp
+++ b/src/Table.cpp
@@ -736,19 +736,14 @@ int Table::columnCount ()
////////////////////////////////////////////////////////////////////////////////
// Removes extraneous output characters, such as:
-// - spaces followed by a newline is collapsed to just a newline, if there is
-// no Bg color.
// - removal of redundant color codes:
// ^[[31mName^[[0m ^[[31mValue^[[0m -> ^[[31mName Value^[[0m
//
// This method is a work in progress.
void Table::optimize (std::string& output) const
{
-/*
- int start = output.length ();
-*/
+// int start = output.length ();
- // \s\n -> \n
/*
Well, how about that!
@@ -770,7 +765,7 @@ void Table::optimize (std::string& output) const
This performance is terrible. To identify the worst offender, Various Timer
objects were added in Table::render, assuming that table sorting is the major
bottleneck. But no, it is Table::optimize that is the problem. After
- commenting out the code below, the results are now:
+ commenting out this method, the results are now:
1000 tasks added in 3 seconds
600 tasks altered in 29 seconds
@@ -784,38 +779,11 @@ void Table::optimize (std::string& output) const
'task history' in 0 seconds
'task ghistory' in 0 seconds
- Much better. Table::optimize is currently disabled.
+ Much better.
*/
- size_t i = 0;
- while ((i = output.find (" \n")) != std::string::npos)
- {
- output = output.substr (0, i) +
- output.substr (i + 8, std::string::npos);
- }
-
- while ((i = output.find (" \n")) != std::string::npos)
- {
- output = output.substr (0, i) +
- output.substr (i + 4, std::string::npos);
- }
-
- while ((i = output.find (" \n")) != std::string::npos)
- {
- output = output.substr (0, i) +
- output.substr (i + 2, std::string::npos);
- }
-
- while ((i = output.find (" \n")) != std::string::npos)
- {
- output = output.substr (0, i) +
- output.substr (i + 1, std::string::npos);
- }
-
-/*
- std::cout << int ((100 * (start - output.length ()) / start))
- << "%" << std::endl;
-*/
+// std::cout << int ((100 * (start - output.length ()) / start))
+// << "%" << std::endl;
}
////////////////////////////////////////////////////////////////////////////////
@@ -1077,11 +1045,17 @@ const std::string Table::render ()
else
output += blanks[col];
+ // Trim right.
+ output.erase (output.find_last_not_of (" ") + 1);
output += "\n";
}
}
else
+ {
+ // Trim right.
+ output.erase (output.find_last_not_of (" ") + 1);
output += "\n";
+ }
}
return output;
diff --git a/src/Table.h b/src/Table.h
index 765c1116a..4048dae70 100644
--- a/src/Table.h
+++ b/src/Table.h
@@ -85,7 +85,6 @@ public:
int rowCount ();
int columnCount ();
const std::string render ();
- void optimize (std::string&) const;
private:
std::string getCell (const int, const int);
@@ -104,6 +103,7 @@ private:
void formatCell (const int, const int, const int, const int, std::vector &, std::string&);
void sort (std::vector &);
void clean (std::string&);
+ void optimize (std::string&) const;
private:
std::vector mColumns;
diff --git a/src/report.cpp b/src/report.cpp
index f6aa675ca..afa460821 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -1205,11 +1205,7 @@ std::string handleReportGHistory (TDB& tdb, T& task, Config& conf)
else
out << "No tasks." << std::endl;
- // Eliminate redundant color codes.
- std::string optimized = out.str ();
- table.optimize (optimized);
-
- return optimized;
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
@@ -2266,7 +2262,7 @@ std::string handleCustomReport (
// Load all pending tasks.
std::vector tasks;
- tdb.pendingT (tasks);
+ tdb.allPendingT (tasks);
handleRecurrence (tdb, tasks);
// Apply filters.
diff --git a/src/tests/benchmark.txt b/src/tests/benchmark.txt
index 78cfba505..c64d3369e 100644
--- a/src/tests/benchmark.txt
+++ b/src/tests/benchmark.txt
@@ -29,11 +29,11 @@
New benchmark:
1..4
ok 1 - Created bench.rc
- # start=1236558734
+ # start=1236565862
# 1000 tasks added in 3 seconds
- # 600 tasks altered in 29 seconds
- # stop=1236558924
- # total=190
+ # 600 tasks altered in 28 seconds
+ # stop=1236566048
+ # total=186
ok 2 - Removed pending.data
ok 3 - Removed completed.data
ok 4 - Removed bench.rc
diff --git a/src/tests/bug.sort.t b/src/tests/bug.sort.t
index 0d0d49eac..c1e4588f5 100755
--- a/src/tests/bug.sort.t
+++ b/src/tests/bug.sort.t
@@ -44,7 +44,6 @@ my $setup = "../task rc:bug_sort.rc add one;"
qx{$setup};
my $output = qx{../task rc:bug_sort.rc list};
-#diag ($output);
like ($output, qr/three.*(?:one.*two|two.*one)/msi, 'list did not hang');
qx{../task rc:bug_sort.rc 1 priority:H};
From 209f7ffb00c89dbf6254d3398a1769f5150edb98 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Mon, 9 Mar 2009 02:52:36 -0400
Subject: [PATCH 061/103] Updated Documentation
- Added new platforms to NEWS file.
---
NEWS | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/NEWS b/NEWS
index 7698ef623..8d2345ad2 100644
--- a/NEWS
+++ b/NEWS
@@ -6,8 +6,10 @@ Task has been built and tested on the following configurations:
- OS X 10.5 Leopard
- Fedora Core 8
- Fedora Core 9
+ - Fedora Core 10
+ - Ubuntu 7 Feisty Fawn
- Ubuntu 8 Hardy Heron
- - Ubuntu 9 Feisty Fawn
+ - Ubunto 8.10 Intrepid Ibex
- Solaris 10
- Cygwin 1.5.25-14
From 9e7844796b89961ddf42998c9eb08d01e2397b80 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Mon, 9 Mar 2009 02:53:44 -0400
Subject: [PATCH 062/103] Updated Documentation
- Added 'beta' download section to main web page.
---
.gitignore | 1 +
html/task.html | 32 ++++++++++++++++++++++++++++----
2 files changed, 29 insertions(+), 4 deletions(-)
diff --git a/.gitignore b/.gitignore
index 3fb778785..e17fbd40d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,4 @@ stamp-h1
Makefile
configure
config.log
+www.xls
diff --git a/html/task.html b/html/task.html
index 64b8cba47..f0e38f23d 100644
--- a/html/task.html
+++ b/html/task.html
@@ -71,7 +71,7 @@
-
Get the Latest Release
+
Get the Latest Stable Release
@@ -116,18 +116,42 @@
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
to help ensure higher quality releases.
-
Fixed bug that caused performance hit during table rendering.
+
Fixed bug that caused large performance hit during table rendering.
Task has been built from source and tested in the following environments:
From 012e47267f523ad8b2d6016da740f50f5656daa3 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Mon, 9 Mar 2009 03:06:41 -0400
Subject: [PATCH 063/103] Bug Fix - concatenated description on modify
- When a task was modified, the new description was concatenated
without spaces.
---
src/parse.cpp | 12 ++++++--
src/tests/bug.concat.t | 66 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 76 insertions(+), 2 deletions(-)
create mode 100755 src/tests/bug.concat.t
diff --git a/src/parse.cpp b/src/parse.cpp
index 99f2d9187..d6528436c 100644
--- a/src/parse.cpp
+++ b/src/parse.cpp
@@ -475,12 +475,20 @@ void parse (
if (isCommand (l) && validCommand (l))
command = l;
else
- descCandidate += arg;
+ {
+ if (descCandidate.length ())
+ descCandidate += " ";
+ descCandidate += std::string (arg);
+ }
}
// Anything else is just considered description.
else
- descCandidate += std::string (arg) + " ";
+ {
+ if (descCandidate.length ())
+ descCandidate += " ";
+ descCandidate += std::string (arg);
+ }
}
}
diff --git a/src/tests/bug.concat.t b/src/tests/bug.concat.t
new file mode 100755
index 000000000..74a82896f
--- /dev/null
+++ b/src/tests/bug.concat.t
@@ -0,0 +1,66 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 5;
+
+# Create the rc file.
+if (open my $fh, '>', 'bug_concat.rc')
+{
+ print $fh "data.location=.\n";
+ close $fh;
+ ok (-r 'bug_concat.rc', 'Created bug_concat.rc');
+}
+
+# When a task is modified like this:
+#
+# % task 1 This is a new description
+#
+# The arguments are concatenated thus:
+#
+# Thisisanewdescription
+
+qx{../task rc:bug_concat.rc add This is the original text};
+
+my $output = qx{../task rc:bug_concat.rc info 1};
+like ($output, qr/Description\s+This is the original text\n/, 'original correct');
+
+qx{../task rc:bug_concat.rc 1 This is the modified text};
+$output = qx{../task rc:bug_concat.rc info 1};
+like ($output, qr/Description\s+This is the modified text\n/, 'modified correct');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'bug_concat.rc';
+ok (!-r 'bug_concat.rc', 'Removed bug_concat.rc');
+
+exit 0;
+
From 751094cffb90458711a4cc357d716351526f93d1 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Mon, 9 Mar 2009 03:09:43 -0400
Subject: [PATCH 064/103] Documentation Update
- Added recent bug fix details.
---
ChangeLog | 1 +
html/task.html | 1 +
2 files changed, 2 insertions(+)
diff --git a/ChangeLog b/ChangeLog
index 1b41b79b0..7b2c3a6ff 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -28,6 +28,7 @@
+ Task now has a large (and growing) test suite and bug regression tests
to help ensure higher quality releases.
+ Fixed bug that caused performance hit during table rendering.
+ + Fixed bug that concatenated a modified description without spaces.
------ old releases ------------------------------
diff --git a/html/task.html b/html/task.html
index f0e38f23d..dd258f2fc 100644
--- a/html/task.html
+++ b/html/task.html
@@ -122,6 +122,7 @@
Task now has a large (and growing) test suite and bug regression tests
to help ensure higher quality releases.
Fixed bug that caused large performance hit during table rendering.
+
Fixed bug that concatenated a modified description without spaces.
From 17de9fec9f182f8599241f40e530e5f0ea7c249f Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Mon, 9 Mar 2009 22:01:08 -0400
Subject: [PATCH 065/103] New Column - recur
- Added new column 'recur' for use in custom reports.
- Implemented Table::ascendingPeriod, Table::descendingPeriod allowing
sorting on the recur column.
- Added unit tests to both use the new column and test the sorting.
- Code cleanup.
---
ChangeLog | 2 ++
html/custom.html | 1 +
html/task.html | 2 ++
src/Table.cpp | 18 +++++++++++++
src/Table.h | 13 ++++++---
src/report.cpp | 17 ++++++++++++
src/task.h | 2 +-
src/tests/recur.t | 67 +++++++++++++++++++++++++++++++++++++++++++++++
src/util.cpp | 15 +++++------
9 files changed, 125 insertions(+), 12 deletions(-)
create mode 100755 src/tests/recur.t
diff --git a/ChangeLog b/ChangeLog
index 7b2c3a6ff..b25b789ba 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -29,6 +29,8 @@
to help ensure higher quality releases.
+ Fixed bug that caused performance hit during table rendering.
+ Fixed bug that concatenated a modified description without spaces.
+ + Added new column 'recur' that displays the recurrence period of any
+ recurring tasks. This column can be added to any custom report.
------ old releases ------------------------------
diff --git a/html/custom.html b/html/custom.html
index 7a970e58e..8b202f5c1 100644
--- a/html/custom.html
+++ b/html/custom.html
@@ -88,6 +88,7 @@ report.mine.sort=priority-,project+
age
active
tags
+
recur
description
diff --git a/html/task.html b/html/task.html
index dd258f2fc..6634516dd 100644
--- a/html/task.html
+++ b/html/task.html
@@ -123,6 +123,8 @@
to help ensure higher quality releases.
Fixed bug that caused large performance hit during table rendering.
Fixed bug that concatenated a modified description without spaces.
+
Added new column 'recur' that displays the recurrence period of any
+ recurring tasks. This column can be added to any custom report.
diff --git a/src/Table.cpp b/src/Table.cpp
index fc0ff1296..071837cdf 100644
--- a/src/Table.cpp
+++ b/src/Table.cpp
@@ -941,6 +941,24 @@ void Table::sort (std::vector & order)
((std::string)*left == "M" && (std::string)*right == "H"))
SWAP
break;
+
+ case ascendingPeriod:
+ if ((std::string)*left == "" && (std::string)*right != "")
+ break;
+ else if ((std::string)*left != "" && (std::string)*right == "")
+ SWAP
+ else if (convertDuration ((std::string)*left) > convertDuration ((std::string)*right))
+ SWAP
+ break;
+
+ case descendingPeriod:
+ if ((std::string)*left != "" && (std::string)*right == "")
+ break;
+ else if ((std::string)*left == "" && (std::string)*right != "")
+ SWAP
+ else if (convertDuration ((std::string)*left) < convertDuration ((std::string)*right))
+ SWAP
+ break;
}
}
}
diff --git a/src/Table.h b/src/Table.h
index 4048dae70..fe098e896 100644
--- a/src/Table.h
+++ b/src/Table.h
@@ -37,9 +37,16 @@ class Table
{
public:
enum just {left, center, right};
- enum order {ascendingNumeric, ascendingCharacter, ascendingPriority,
- ascendingDate, descendingNumeric, descendingCharacter,
- descendingPriority, descendingDate};
+ enum order {ascendingNumeric,
+ ascendingCharacter,
+ ascendingPriority,
+ ascendingDate,
+ ascendingPeriod,
+ descendingNumeric,
+ descendingCharacter,
+ descendingPriority,
+ descendingDate,
+ descendingPeriod};
enum sizing {minimum = -1, flexible = 0};
Table ();
diff --git a/src/report.cpp b/src/report.cpp
index afa460821..6f25c90a4 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -2447,6 +2447,16 @@ std::string handleCustomReport (
table.addCell (row, columnCount, tasks[row].getDescription ());
}
+ else if (*col == "recur")
+ {
+ table.addColumn ("Recur");
+ table.setColumnWidth (columnCount, Table::minimum);
+ table.setColumnJustification (columnCount, Table::right);
+
+ for (unsigned int row = 0; row < tasks.size (); ++row)
+ table.addCell (row, columnCount, tasks[row].getAttribute ("recur"));
+ }
+
// Common to all columns.
// Add underline.
if (conf.get (std::string ("color"), true) || conf.get (std::string ("_forcecolor"), false))
@@ -2487,6 +2497,12 @@ std::string handleCustomReport (
Table::ascendingDate :
Table::descendingDate));
+ else if (column == "recur")
+ table.sortOn (columnIndex[column],
+ (direction == '+' ?
+ Table::ascendingPeriod :
+ Table::descendingPeriod));
+
else
table.sortOn (columnIndex[column],
(direction == '+' ?
@@ -2567,6 +2583,7 @@ void validReportColumns (const std::vector & columns)
*it != "age" &&
*it != "active" &&
*it != "tags" &&
+ *it != "recur" &&
*it != "description")
bad.push_back (*it);
diff --git a/src/task.h b/src/task.h
index 03a5d5f7d..925b75811 100644
--- a/src/task.h
+++ b/src/task.h
@@ -126,7 +126,7 @@ void formatTimeDeltaDays (std::string&, time_t);
std::string formatSeconds (time_t);
const std::string uuid ();
const char* optionalBlankLine (Config&);
-int convertDuration (std::string&);
+int convertDuration (const std::string&);
std::string expandPath (const std::string&);
#ifdef SOLARIS
diff --git a/src/tests/recur.t b/src/tests/recur.t
new file mode 100755
index 000000000..96a251bd2
--- /dev/null
+++ b/src/tests/recur.t
@@ -0,0 +1,67 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 6;
+
+# Create the rc file.
+if (open my $fh, '>', 'recur.rc')
+{
+ print $fh "data.location=.\n",
+ "report.asc.columns=id,recur,description\n",
+ "report.asc.sort=recur+\n",
+ "report.desc.columns=id,recur,description\n",
+ "report.desc.sort=recur-\n";
+ close $fh;
+ ok (-r 'recur.rc', 'Created recur.rc');
+}
+
+# Create a few recurring tasks, and test the sort order of the recur column.
+qx{../task rc:recur.rc add due:tomorrow recur:daily first};
+qx{../task rc:recur.rc add due:tomorrow recur:weekly second};
+qx{../task rc:recur.rc add due:tomorrow recur:3d third};
+
+my $output = qx{../task rc:recur.rc asc};
+like ($output, qr/first .* third .* second/msx, 'daily 3d weekly');
+
+$output = qx{../task rc:recur.rc desc};
+like ($output, qr/second .* third .* first/msx, 'weekly 3d daily');
+
+# Cleanup.
+unlink 'shadow.txt';
+ok (!-r 'shadow.txt', 'Removed shadow.txt');
+
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'recur.rc';
+ok (!-r 'recur.rc', 'Removed recur.rc');
+
+exit 0;
+
diff --git a/src/util.cpp b/src/util.cpp
index bc1bea9f2..7f1e6b911 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -241,9 +241,9 @@ const std::string uuid ()
////////////////////////////////////////////////////////////////////////////////
// Recognize the following constructs, and return the number of days represented
-int convertDuration (std::string& input)
+int convertDuration (const std::string& input)
{
- input = lowerCase (input);
+ std::string lower_input = lowerCase (input);
Date today;
std::vector supported;
@@ -263,7 +263,7 @@ int convertDuration (std::string& input)
supported.push_back ("yearly");
std::vector matches;
- if (autoComplete (input, supported, matches) == 1)
+ if (autoComplete (lower_input, supported, matches) == 1)
{
std::string found = matches[0];
@@ -279,19 +279,18 @@ int convertDuration (std::string& input)
}
// Support \d+ d|w|m|q|y
-
else
{
// Verify all digits followed by d, w, m, q, or y.
- unsigned int length = input.length ();
+ unsigned int length = lower_input.length ();
for (unsigned int i = 0; i < length; ++i)
{
- if (! isdigit (input[i]) &&
+ if (! isdigit (lower_input[i]) &&
i == length - 1)
{
- int number = ::atoi (input.substr (0, i).c_str ());
+ int number = ::atoi (lower_input.substr (0, i).c_str ());
- switch (input[length - 1])
+ switch (lower_input[length - 1])
{
case 'd': return number * 1; break;
case 'w': return number * 7; break;
From 1999e38ba53456cac1817e585efa649dd1b34968 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Mon, 9 Mar 2009 22:12:49 -0400
Subject: [PATCH 066/103] Colorization - color.recurring
- Added support for "color.recurring" configuration variable to
colorize recurring tasks.
- Updated docs.
---
ChangeLog | 2 ++
html/config.html | 3 ++-
html/task.html | 2 ++
src/Config.cpp | 1 +
src/rules.cpp | 57 +++++++++++++++++++++++++++++-------------------
5 files changed, 41 insertions(+), 24 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index b25b789ba..4dc041060 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -31,6 +31,8 @@
+ Fixed bug that concatenated a modified description without spaces.
+ Added new column 'recur' that displays the recurrence period of any
recurring tasks. This column can be added to any custom report.
+ + Added support for "color.recurring" configuration variable which
+ specifies the color of recurring tasks.
------ old releases ------------------------------
diff --git a/html/config.html b/html/config.html
index fd4bc71a4..20b211fcf 100644
--- a/html/config.html
+++ b/html/config.html
@@ -218,7 +218,8 @@
color.pri.L
color.pri.none
color.active
- color.tagged
+ color.tagged
+ color.recurring
These are the coloration rules. They correspond to a particular
diff --git a/html/task.html b/html/task.html
index 6634516dd..04bc81f96 100644
--- a/html/task.html
+++ b/html/task.html
@@ -125,6 +125,8 @@
Fixed bug that concatenated a modified description without spaces.
Added new column 'recur' that displays the recurrence period of any
recurring tasks. This column can be added to any custom report.
+
Added support for "color.recurring" configuration variable which
+ specifies the color of recurring tasks.
diff --git a/src/Config.cpp b/src/Config.cpp
index 64e07b04c..643c0ac16 100644
--- a/src/Config.cpp
+++ b/src/Config.cpp
@@ -144,6 +144,7 @@ void Config::createDefault (const std::string& home)
fprintf (out, "#color.tag.bug=yellow\n");
fprintf (out, "#color.project.garden=on_green\n");
fprintf (out, "#color.keyword.car=on_blue\n");
+ fprintf (out, "#color.recurring=on_red\n");
fprintf (out, "#shadow.file=%s/shadow.txt\n", dataDir.c_str ());
fprintf (out, "#shadow.command=list\n");
fprintf (out, "#shadow.notify=on\n");
diff --git a/src/rules.cpp b/src/rules.cpp
index f33354c9f..cac04156e 100644
--- a/src/rules.cpp
+++ b/src/rules.cpp
@@ -89,6 +89,17 @@ void autoColorize (
// Note: fg, bg already contain colors specifically assigned via command.
// Note: These rules form a hierarchy - the last rule is king.
+ // Colorization of the recurring.
+ if (gsFg["color.recurring"] != Text::nocolor ||
+ gsBg["color.recurring"] != Text::nocolor)
+ {
+ if (task.getAttribute ("recur") != "")
+ {
+ fg = gsFg["color.recurring"];
+ bg = gsBg["color.recurring"];
+ }
+ }
+
// Colorization of the tagged.
if (gsFg["color.tagged"] != Text::nocolor ||
gsBg["color.tagged"] != Text::nocolor)
@@ -157,29 +168,6 @@ void autoColorize (
}
}
- // Colorization of the due and overdue.
- std::string due = task.getAttribute ("due");
- if (due != "")
- {
- Date dueDate (::atoi (due.c_str ()));
- Date now;
- Date then (now + conf.get ("due", 7) * 86400);
-
- // Overdue
- if (dueDate < now)
- {
- fg = gsFg["color.overdue"];
- bg = gsBg["color.overdue"];
- }
-
- // Imminent
- else if (dueDate < then)
- {
- fg = gsFg["color.due"];
- bg = gsBg["color.due"];
- }
- }
-
// Colorization by tag value.
std::map ::iterator it;
for (it = gsFg.begin (); it != gsFg.end (); ++it)
@@ -223,6 +211,29 @@ void autoColorize (
}
}
}
+
+ // Colorization of the due and overdue.
+ std::string due = task.getAttribute ("due");
+ if (due != "")
+ {
+ Date dueDate (::atoi (due.c_str ()));
+ Date now;
+ Date then (now + conf.get ("due", 7) * 86400);
+
+ // Overdue
+ if (dueDate < now)
+ {
+ fg = gsFg["color.overdue"];
+ bg = gsBg["color.overdue"];
+ }
+
+ // Imminent
+ else if (dueDate < then)
+ {
+ fg = gsFg["color.due"];
+ bg = gsBg["color.due"];
+ }
+ }
}
////////////////////////////////////////////////////////////////////////////////
From 0ff33d1c1690e6ad50b1c499343e66e654b5c23d Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Mon, 9 Mar 2009 22:53:54 -0400
Subject: [PATCH 067/103] Version command changes
- Added color.recurring to the list of valid config values.
- Added message to "version" command hinting that folks should look
periodically for updated versions of task. Task does not "call home"
and check for updates (and never will), and so it is easy to not
realize that there may be newer versions of task with bug fixes and
new features.
---
src/command.cpp | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/src/command.cpp b/src/command.cpp
index 03e6e473d..a129323af 100644
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -307,7 +307,9 @@ std::string handleVersion (Config& conf)
link.setColumnWidth (0, Table::flexible);
link.setColumnJustification (0, Table::left);
link.addCell (link.addRow (), 0,
- "See http://www.beckingham.net/task.html for the latest releases and a full tutorial.");
+ "See http://www.beckingham.net/task.html for the latest releases and a "
+ "full tutorial. New releases containing fixes and enhancements are "
+ "released frequently.");
// Create a table for output.
Table table;
@@ -363,10 +365,10 @@ std::string handleVersion (Config& conf)
// These are the regular configuration variables.
std::string recognized =
"blanklines color color.active color.due color.overdue color.pri.H "
- "color.pri.L color.pri.M color.pri.none color.tagged confirmation curses "
- "data.location dateformat default.command default.priority defaultwidth due "
- "monthsperline nag newest next oldest project shadow.command shadow.file "
- "shadow.notify";
+ "color.pri.L color.pri.M color.pri.none color.recurring color.tagged "
+ "confirmation curses data.location dateformat default.command "
+ "default.priority defaultwidth due monthsperline nag newest next oldest "
+ "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
From 6fade845352b83bd45bdb43736e342cc25094e55 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Tue, 10 Mar 2009 00:08:40 -0400
Subject: [PATCH 068/103] Unit Tests - color.*, abbreviation
- Added unit tests for all auto coloration configuration settings.
- Tweaked colorization rule precedence to allow color.due to override
the built-in coloration of due tasks.
---
src/rules.cpp | 24 +++++++-------
src/tests/abbreviation.t | 26 ++++++++++++++--
src/tests/color.active.t | 60 +++++++++++++++++++++++++++++++++++
src/tests/color.due.t | 59 +++++++++++++++++++++++++++++++++++
src/tests/color.keyword.t | 62 +++++++++++++++++++++++++++++++++++++
src/tests/color.overdue.t | 59 +++++++++++++++++++++++++++++++++++
src/tests/color.project.t | 59 +++++++++++++++++++++++++++++++++++
src/tests/color.recurring.t | 59 +++++++++++++++++++++++++++++++++++
src/tests/color.tag.t | 62 +++++++++++++++++++++++++++++++++++++
src/tests/color.tagged.t | 59 +++++++++++++++++++++++++++++++++++
10 files changed, 515 insertions(+), 14 deletions(-)
create mode 100755 src/tests/color.active.t
create mode 100755 src/tests/color.due.t
create mode 100755 src/tests/color.keyword.t
create mode 100755 src/tests/color.overdue.t
create mode 100755 src/tests/color.project.t
create mode 100755 src/tests/color.recurring.t
create mode 100755 src/tests/color.tag.t
create mode 100755 src/tests/color.tagged.t
diff --git a/src/rules.cpp b/src/rules.cpp
index cac04156e..5744dd3ca 100644
--- a/src/rules.cpp
+++ b/src/rules.cpp
@@ -87,18 +87,7 @@ void autoColorize (
Config& conf)
{
// Note: fg, bg already contain colors specifically assigned via command.
- // Note: These rules form a hierarchy - the last rule is king.
-
- // Colorization of the recurring.
- if (gsFg["color.recurring"] != Text::nocolor ||
- gsBg["color.recurring"] != Text::nocolor)
- {
- if (task.getAttribute ("recur") != "")
- {
- fg = gsFg["color.recurring"];
- bg = gsBg["color.recurring"];
- }
- }
+ // Note: These rules form a hierarchy - the last rule is King.
// Colorization of the tagged.
if (gsFg["color.tagged"] != Text::nocolor ||
@@ -234,6 +223,17 @@ void autoColorize (
bg = gsBg["color.due"];
}
}
+
+ // Colorization of the recurring.
+ if (gsFg["color.recurring"] != Text::nocolor ||
+ gsBg["color.recurring"] != Text::nocolor)
+ {
+ if (task.getAttribute ("recur") != "")
+ {
+ fg = gsFg["color.recurring"];
+ bg = gsBg["color.recurring"];
+ }
+ }
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/src/tests/abbreviation.t b/src/tests/abbreviation.t
index 4d9b27515..18d330e65 100755
--- a/src/tests/abbreviation.t
+++ b/src/tests/abbreviation.t
@@ -28,7 +28,7 @@
use strict;
use warnings;
-use Test::More tests => 15;
+use Test::More tests => 22;
# Create the rc file.
if (open my $fh, '>', 'abbrev.rc')
@@ -38,7 +38,7 @@ if (open my $fh, '>', 'abbrev.rc')
ok (-r 'abbrev.rc', 'Created abbrev.rc');
}
-# Test the add command.
+# Test the priority attribute abbrevations.
qx{../task rc:abbrev.rc add priority:H with};
qx{../task rc:abbrev.rc add without};
@@ -66,6 +66,28 @@ $output = qx{../task rc:abbrev.rc list pri:H};
like ($output, qr/\bwith\b/, 'pri:H with');
unlike ($output, qr/\bwithout\b/, 'pri:H without');
+# Test the version command abbreviations.
+$output = qx{../task version};
+like ($output, qr/ABSOLUTELY NO WARRANTY/, 'version');
+
+$output = qx{../task versio};
+like ($output, qr/ABSOLUTELY NO WARRANTY/, 'versio');
+
+$output = qx{../task versi};
+like ($output, qr/ABSOLUTELY NO WARRANTY/, 'versi');
+
+$output = qx{../task vers};
+like ($output, qr/ABSOLUTELY NO WARRANTY/, 'vers');
+
+$output = qx{../task ver};
+like ($output, qr/ABSOLUTELY NO WARRANTY/, 'ver');
+
+$output = qx{../task ve};
+like ($output, qr/ABSOLUTELY NO WARRANTY/, 've');
+
+$output = qx{../task v};
+like ($output, qr/ABSOLUTELY NO WARRANTY/, 'v');
+
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
diff --git a/src/tests/color.active.t b/src/tests/color.active.t
new file mode 100755
index 000000000..0ad678223
--- /dev/null
+++ b/src/tests/color.active.t
@@ -0,0 +1,60 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 5;
+
+# Create the rc file.
+if (open my $fh, '>', 'color.rc')
+{
+ print $fh "data.location=.\n",
+ "color.active=red\n",
+ "_forcecolor=1\n";
+ close $fh;
+ ok (-r 'color.rc', 'Created color.rc');
+}
+
+# Test the add command.
+qx{../task rc:color.rc add nothing};
+qx{../task rc:color.rc add red};
+qx{../task rc:color.rc start 2};
+my $output = qx{../task rc:color.rc list};
+
+like ($output, qr/ (?!<\033\[\d\dm) .* nothing .* (?!>\033\[0m) /x, 'none');
+like ($output, qr/ \033\[31m .* red .* \033\[0m /x, 'color.active');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'color.rc';
+ok (!-r 'color.rc', 'Removed color.rc');
+
+exit 0;
+
diff --git a/src/tests/color.due.t b/src/tests/color.due.t
new file mode 100755
index 000000000..af1f0077e
--- /dev/null
+++ b/src/tests/color.due.t
@@ -0,0 +1,59 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 5;
+
+# Create the rc file.
+if (open my $fh, '>', 'color.rc')
+{
+ print $fh "data.location=.\n",
+ "color.due=red\n",
+ "_forcecolor=1\n";
+ close $fh;
+ ok (-r 'color.rc', 'Created color.rc');
+}
+
+# Test the add command.
+qx{../task rc:color.rc add due:eoy nothing};
+qx{../task rc:color.rc add due:tomorrow red};
+my $output = qx{../task rc:color.rc list};
+
+like ($output, qr/ (?!<\033\[\d\dm) \d{1,2}\/\d{1,2}\/\d{4} (?!>\033\[0m) .* nothing /x, 'none');
+like ($output, qr/ \033\[31m .* red .* \033\[0m/x, 'color.due');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'color.rc';
+ok (!-r 'color.rc', 'Removed color.rc');
+
+exit 0;
+
diff --git a/src/tests/color.keyword.t b/src/tests/color.keyword.t
new file mode 100755
index 000000000..4e99e7400
--- /dev/null
+++ b/src/tests/color.keyword.t
@@ -0,0 +1,62 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 6;
+
+# Create the rc file.
+if (open my $fh, '>', 'color.rc')
+{
+ print $fh "data.location=.\n",
+ "color.keyword.red=red\n",
+ "color.keyword.green=green\n",
+ "_forcecolor=1\n";
+ close $fh;
+ ok (-r 'color.rc', 'Created color.rc');
+}
+
+# Test the add command.
+qx{../task rc:color.rc add nothing};
+qx{../task rc:color.rc add red};
+qx{../task rc:color.rc add green};
+my $output = qx{../task rc:color.rc list};
+
+like ($output, qr/ (?!<\033\[\d\dm) .* nothing .* (?!>\033\[0m) /x, 'none');
+like ($output, qr/ \033\[31m .* red .* \033\[0m /x, 'color.keyword.red');
+like ($output, qr/ \033\[32m .* green .* \033\[0m /x, 'color.keyword.green');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'color.rc';
+ok (!-r 'color.rc', 'Removed color.rc');
+
+exit 0;
+
diff --git a/src/tests/color.overdue.t b/src/tests/color.overdue.t
new file mode 100755
index 000000000..9555a92cd
--- /dev/null
+++ b/src/tests/color.overdue.t
@@ -0,0 +1,59 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 5;
+
+# Create the rc file.
+if (open my $fh, '>', 'color.rc')
+{
+ print $fh "data.location=.\n",
+ "color.overdue=red\n",
+ "_forcecolor=1\n";
+ close $fh;
+ ok (-r 'color.rc', 'Created color.rc');
+}
+
+# Test the add command.
+qx{../task rc:color.rc add due:tomorrow nothing};
+qx{../task rc:color.rc add due:yesterday red};
+my $output = qx{../task rc:color.rc list};
+
+like ($output, qr/ (?!<\033\[\d\dm) \d{1,2}\/\d{1,2}\/\d{4} (?!>\033\[0m) .* nothing /x, 'none');
+like ($output, qr/ \033\[31m .* red .* \033\[0m/x, 'color.overdue');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'color.rc';
+ok (!-r 'color.rc', 'Removed color.rc');
+
+exit 0;
+
diff --git a/src/tests/color.project.t b/src/tests/color.project.t
new file mode 100755
index 000000000..2b90ec59c
--- /dev/null
+++ b/src/tests/color.project.t
@@ -0,0 +1,59 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 5;
+
+# Create the rc file.
+if (open my $fh, '>', 'color.rc')
+{
+ print $fh "data.location=.\n",
+ "color.project.x=red\n",
+ "_forcecolor=1\n";
+ close $fh;
+ ok (-r 'color.rc', 'Created color.rc');
+}
+
+# Test the add command.
+qx{../task rc:color.rc add nothing};
+qx{../task rc:color.rc add project:x red};
+my $output = qx{../task rc:color.rc list};
+
+like ($output, qr/ (?!<\033\[\d\dm) .* nothing .* (?!>\033\[0m) /x, 'none');
+like ($output, qr/ \033\[31m .* red .* \033\[0m /x, 'color.project.red');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'color.rc';
+ok (!-r 'color.rc', 'Removed color.rc');
+
+exit 0;
+
diff --git a/src/tests/color.recurring.t b/src/tests/color.recurring.t
new file mode 100755
index 000000000..27990b1aa
--- /dev/null
+++ b/src/tests/color.recurring.t
@@ -0,0 +1,59 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 5;
+
+# Create the rc file.
+if (open my $fh, '>', 'color.rc')
+{
+ print $fh "data.location=.\n",
+ "color.recurring=red\n",
+ "_forcecolor=1\n";
+ close $fh;
+ ok (-r 'color.rc', 'Created color.rc');
+}
+
+# Test the add command.
+qx{../task rc:color.rc add nothing};
+qx{../task rc:color.rc add due:tomorrow recur:1w red};
+my $output = qx{../task rc:color.rc list};
+
+like ($output, qr/ (?!<\033\[\d\dm) .* nothing .* (?!>\033\[0m) /x, 'none');
+like ($output, qr/ \033\[31m .* red .* \033\[0m /x, 'color.recurring');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'color.rc';
+ok (!-r 'color.rc', 'Removed color.rc');
+
+exit 0;
+
diff --git a/src/tests/color.tag.t b/src/tests/color.tag.t
new file mode 100755
index 000000000..da870e39e
--- /dev/null
+++ b/src/tests/color.tag.t
@@ -0,0 +1,62 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 6;
+
+# Create the rc file.
+if (open my $fh, '>', 'color.rc')
+{
+ print $fh "data.location=.\n",
+ "color.tag.red=red\n",
+ "color.tag.green=green\n",
+ "_forcecolor=1\n";
+ close $fh;
+ ok (-r 'color.rc', 'Created color.rc');
+}
+
+# Test the add command.
+qx{../task rc:color.rc add nothing};
+qx{../task rc:color.rc add +red red};
+qx{../task rc:color.rc add +green green};
+my $output = qx{../task rc:color.rc list};
+
+like ($output, qr/ (?!<\033\[\d\dm) .* nothing .* (?!>\033\[0m) /x, 'none');
+like ($output, qr/ \033\[31m .* red .* \033\[0m /x, 'color.tag.red');
+like ($output, qr/ \033\[32m .* green .* \033\[0m /x, 'color.tag.green');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'color.rc';
+ok (!-r 'color.rc', 'Removed color.rc');
+
+exit 0;
+
diff --git a/src/tests/color.tagged.t b/src/tests/color.tagged.t
new file mode 100755
index 000000000..947a467e9
--- /dev/null
+++ b/src/tests/color.tagged.t
@@ -0,0 +1,59 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 5;
+
+# Create the rc file.
+if (open my $fh, '>', 'color.rc')
+{
+ print $fh "data.location=.\n",
+ "color.tagged=red\n",
+ "_forcecolor=1\n";
+ close $fh;
+ ok (-r 'color.rc', 'Created color.rc');
+}
+
+# Test the add command.
+qx{../task rc:color.rc add nothing};
+qx{../task rc:color.rc add +tag red};
+my $output = qx{../task rc:color.rc list};
+
+like ($output, qr/ (?!<\033\[\d\dm) .* nothing .* (?!>\033\[0m) /x, 'none');
+like ($output, qr/ \033\[31m .* red .* \033\[0m /x, 'color.tagged');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'color.rc';
+ok (!-r 'color.rc', 'Removed color.rc');
+
+exit 0;
+
From 9f278b1ffcbe6735b242c391ba3c433b7ab8fab5 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Tue, 10 Mar 2009 00:22:23 -0400
Subject: [PATCH 069/103] Unit Tests - export
- Added unit tests to export tasks and compare.
---
src/tests/export.t | 72 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 72 insertions(+)
create mode 100755 src/tests/export.t
diff --git a/src/tests/export.t b/src/tests/export.t
new file mode 100755
index 000000000..4218a3c10
--- /dev/null
+++ b/src/tests/export.t
@@ -0,0 +1,72 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 7;
+
+# Create the rc file.
+if (open my $fh, '>', 'export.rc')
+{
+ print $fh "data.location=.\n";
+ close $fh;
+ ok (-r 'export.rc', 'Created export.rc');
+}
+
+# Add two tasks, export, examine result.
+qx{../task rc:export.rc add priority:H project:A one};
+qx{../task rc:export.rc add +tag1 +tag2 two};
+qx{../task rc:export.rc export ./export.txt};
+
+my @lines;
+if (open my $fh, '<', './export.txt')
+{
+ @lines = <$fh>;
+ close $fh;
+}
+
+my $line1 = qr/'id','uuid','status','tags','entry','start','due','end','project','priority','fg','bg','description'\n/;
+my $line2 = qr/'.{8}-.{4}-.{4}-.{4}-.{12}','pending','',\d+,,,,'A','H',,,'one'\n/;
+my $line3 = qr/'.{8}-.{4}-.{4}-.{4}-.{12}','pending','tag1 tag2',\d+,,,,,,,,'two'\n/;
+
+like ($lines[0], $line1, "export line one");
+like ($lines[1], $line2, "export line two");
+like ($lines[2], $line3, "export line three");
+
+# Cleanup.
+unlink 'export.txt';
+ok (!-r 'export.txt', 'Removed export.txt');
+
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'export.rc';
+ok (!-r 'export.rc', 'Removed export.rc');
+
+exit 0;
+
From dc946e175e0b09f2d1922d5f7b1b6fe7e3fad585 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Tue, 10 Mar 2009 14:32:32 -0400
Subject: [PATCH 070/103] Unit Tests - completed, delete
- Added unit tests to verify that the completed.data file is not
created until the first report is run after the task is marked
as done.
- Added unit tests to verify that delete/undelete work as expected.
---
src/tests/completed.t | 64 +++++++++++++++++++++++++++++++++++
src/tests/delete.t | 77 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 141 insertions(+)
create mode 100755 src/tests/completed.t
create mode 100755 src/tests/delete.t
diff --git a/src/tests/completed.t b/src/tests/completed.t
new file mode 100755
index 000000000..a53c7e652
--- /dev/null
+++ b/src/tests/completed.t
@@ -0,0 +1,64 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 6;
+
+# Create the rc file.
+if (open my $fh, '>', 'completed.rc')
+{
+ print $fh "data.location=.\n",
+ "confirmation=no\n";
+ close $fh;
+ ok (-r 'completed.rc', 'Created completed.rc');
+}
+
+# Add two tasks, mark 1 as done, the other as deleted.
+qx{../task rc:completed.rc add one};
+qx{../task rc:completed.rc add two};
+qx{../task rc:completed.rc 1 done};
+qx{../task rc:completed.rc 2 delete};
+
+# Generate completed report.
+my $output = qx{../task rc:completed.rc completed};
+like ($output, qr/one/, 'one -> completed');
+unlike ($output, qr/two/, 'two -> deleted');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'completed.data';
+ok (!-r 'completed.data', 'Removed completed.data');
+
+unlink 'completed.rc';
+ok (!-r 'completed.rc', 'Removed completed.rc');
+
+exit 0;
+
diff --git a/src/tests/delete.t b/src/tests/delete.t
new file mode 100755
index 000000000..9f36f517b
--- /dev/null
+++ b/src/tests/delete.t
@@ -0,0 +1,77 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 16;
+
+# Create the rc file.
+if (open my $fh, '>', 'undelete.rc')
+{
+ print $fh "data.location=.\n";
+ close $fh;
+ ok (-r 'undelete.rc', 'Created undelete.rc');
+}
+
+# Add a task, delete it, undelete it.
+my $output = qx{../task rc:undelete.rc add one; ../task rc:undelete.rc info 1};
+ok (-r 'pending.data', 'pending.data created');
+like ($output, qr/Status\s+Pending\n/, 'Pending');
+
+$output = qx{../task rc:undelete.rc delete 1; ../task rc:undelete.rc info 1};
+like ($output, qr/Status\s+Deleted\n/, 'Deleted');
+ok (! -r 'completed.data', 'completed.data not created');
+
+$output = qx{../task rc:undelete.rc undelete 1; ../task rc:undelete.rc info 1};
+like ($output, qr/Status\s+Pending\n/, 'Pending');
+ok (! -r 'completed.data', 'completed.data not created');
+
+$output = qx{../task rc:undelete.rc delete 1; ../task rc:undelete.rc list};
+like ($output, qr/^No matches/, 'No matches');
+ok (-r 'completed.data', 'completed.data created');
+
+$output = qx{../task rc:undelete.rc undelete 1};
+like ($output, qr/reliably undeleted/, 'can only be reliable undeleted...');
+
+$output = qx{../task rc:undelete.rc info 1};
+like ($output, qr/No matches./, 'no matches');
+
+# Cleanup.
+ok (-r 'pending.data', 'Need to remove pending.data');
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+ok (-r 'completed.data', 'Need to remove completed.data');
+unlink 'completed.data';
+ok (!-r 'completed.data', 'Removed completed.data');
+
+unlink 'undelete.rc';
+ok (!-r 'undelete.rc', 'Removed undelete.rc');
+
+exit 0;
+
From d174bb11437ac5201d39626c13c9cc23d3a8e8c1 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Tue, 10 Mar 2009 15:21:29 -0400
Subject: [PATCH 071/103] Bug Workaround - locking
- Added support for the "locking" configuration variable that disables
file locking. This can be helpful to folks who use task on Solaris,
and store their task data files on an NFS mount.
---
ChangeLog | 2 ++
html/config.html | 15 +++++++++++++++
html/task.html | 2 ++
src/Config.cpp | 13 ++++++++-----
src/TDB.cpp | 30 ++++++++++++++++++++++--------
src/TDB.h | 3 +++
src/command.cpp | 4 ++--
src/task.cpp | 4 ++++
8 files changed, 58 insertions(+), 15 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 4dc041060..de3524351 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -33,6 +33,8 @@
recurring tasks. This column can be added to any custom report.
+ Added support for "color.recurring" configuration variable which
specifies the color of recurring tasks.
+ + Added support for "locking" configuration variable that controls whether
+ file locking is used.
------ old releases ------------------------------
diff --git a/html/config.html b/html/config.html
index 20b211fcf..c614f3ad0 100644
--- a/html/config.html
+++ b/html/config.html
@@ -325,6 +325,21 @@ ID Project Pri Description
whenever the shadow file is updated by some task command.
+
locking
+
+
+ Determines whether task uses file locking when accessing the pending.data
+ and completed.data files. Default to "on". Solaris users who store
+ the task data files on an NFS mount may need to set locking to "off".
+
+
+
+ Note that setting this value to "off" is dangerous. It means that
+ another program may write to the task.pending file when task is
+ attempting to do the same.
+
+
+
Note that the command:
diff --git a/html/task.html b/html/task.html
index 04bc81f96..9f4ef60cc 100644
--- a/html/task.html
+++ b/html/task.html
@@ -127,6 +127,8 @@
recurring tasks. This column can be added to any custom report.
Added support for "color.recurring" configuration variable which
specifies the color of recurring tasks.
+
Added support for "locking" configuration variable that controls whether
+ file locking is used.
diff --git a/src/Config.cpp b/src/Config.cpp
index 643c0ac16..7ac95b1a7 100644
--- a/src/Config.cpp
+++ b/src/Config.cpp
@@ -132,6 +132,7 @@ void Config::createDefault (const std::string& home)
fprintf (out, "color=on\n");
fprintf (out, "due=7\n");
fprintf (out, "nag=You have higher priority tasks.\n");
+ fprintf (out, "locking=on\n");
fprintf (out, "color.overdue=bold_red\n");
fprintf (out, "color.due=bold_yellow\n");
@@ -222,11 +223,13 @@ bool Config::get (const std::string& key, bool default_value)
{
std::string value = lowerCase ((*this)[key]);
- if (value == "t" ||
- value == "true" ||
- value == "1" ||
- value == "yes" ||
- value == "on")
+ if (value == "t" ||
+ value == "true" ||
+ value == "1" ||
+ value == "yes" ||
+ value == "on" ||
+ value == "enable" ||
+ value == "enabled")
return true;
return false;
diff --git a/src/TDB.cpp b/src/TDB.cpp
index 98a67e119..c77febb7a 100644
--- a/src/TDB.cpp
+++ b/src/TDB.cpp
@@ -38,6 +38,7 @@ TDB::TDB ()
: mPendingFile ("")
, mCompletedFile ("")
, mId (1)
+, mNoLock (false)
{
}
@@ -289,6 +290,9 @@ bool TDB::modifyT (const T& t)
////////////////////////////////////////////////////////////////////////////////
bool TDB::lock (FILE* file) const
{
+ if (mNoLock)
+ return true;
+
return flock (fileno (file), LOCK_EX) ? false : true;
}
@@ -300,8 +304,9 @@ bool TDB::overwritePending (std::vector & all)
if ((out = fopen (mPendingFile.c_str (), "w")))
{
int retry = 0;
- while (flock (fileno (out), LOCK_EX) && ++retry <= 3)
- delay (0.25);
+ if (!mNoLock)
+ while (flock (fileno (out), LOCK_EX) && ++retry <= 3)
+ delay (0.1);
std::vector ::iterator it;
for (it = all.begin (); it != all.end (); ++it)
@@ -322,8 +327,9 @@ bool TDB::writePending (const T& t)
if ((out = fopen (mPendingFile.c_str (), "a")))
{
int retry = 0;
- while (flock (fileno (out), LOCK_EX) && ++retry <= 3)
- delay (0.25);
+ if (!mNoLock)
+ while (flock (fileno (out), LOCK_EX) && ++retry <= 3)
+ delay (0.1);
fputs (t.compose ().c_str (), out);
@@ -342,8 +348,9 @@ bool TDB::writeCompleted (const T& t)
if ((out = fopen (mCompletedFile.c_str (), "a")))
{
int retry = 0;
- while (flock (fileno (out), LOCK_EX) && ++retry <= 3)
- delay (0.25);
+ if (!mNoLock)
+ while (flock (fileno (out), LOCK_EX) && ++retry <= 3)
+ delay (0.1);
fputs (t.compose ().c_str (), out);
@@ -367,8 +374,9 @@ bool TDB::readLockedFile (
if ((in = fopen (file.c_str (), "r")))
{
int retry = 0;
- while (flock (fileno (in), LOCK_EX) && ++retry <= 3)
- delay (0.25);
+ if (!mNoLock)
+ while (flock (fileno (in), LOCK_EX) && ++retry <= 3)
+ delay (0.1);
char line[T_LINE_MAX];
while (fgets (line, T_LINE_MAX, in))
@@ -432,4 +440,10 @@ int TDB::nextId ()
}
////////////////////////////////////////////////////////////////////////////////
+void TDB::noLock ()
+{
+ mNoLock = true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
diff --git a/src/TDB.h b/src/TDB.h
index b354d97f3..49a68fa11 100644
--- a/src/TDB.h
+++ b/src/TDB.h
@@ -51,6 +51,8 @@ public:
int gc ();
int nextId ();
+ void noLock ();
+
private:
bool lock (FILE*) const;
bool overwritePending (std::vector &);
@@ -62,6 +64,7 @@ private:
std::string mPendingFile;
std::string mCompletedFile;
int mId;
+ bool mNoLock;
};
#endif
diff --git a/src/command.cpp b/src/command.cpp
index a129323af..0a6e9756a 100644
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -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 monthsperline nag newest next oldest "
- "project shadow.command shadow.file shadow.notify";
+ "default.priority defaultwidth due locking monthsperline nag newest next "
+ "oldest 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
diff --git a/src/task.cpp b/src/task.cpp
index 04c73c3e6..00b21d9cb 100644
--- a/src/task.cpp
+++ b/src/task.cpp
@@ -299,6 +299,10 @@ int main (int argc, char** argv)
std::string dataLocation = expandPath (conf.get ("data.location"));
tdb.dataDirectory (dataLocation);
+ // Allow user override of file locking. Solaris/NFS machines may want this.
+ if (! conf.get ("locking", true))
+ tdb.noLock ();
+
// Check for silly shadow file settings.
std::string shadowFile = expandPath (conf.get ("shadow.file"));
if (shadowFile != "")
From 6d8cb5181fb37725f4064afa0413956ad404def6 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Tue, 10 Mar 2009 15:40:48 -0400
Subject: [PATCH 072/103] Bug Fix - unit test tdb.t
- Fixed two failing unit tests in tdb.t.cpp, which were both due to
incorrect test logic, rather than a TDB bug.
---
src/TDB.cpp | 4 ++++
src/tests/tdb.t.cpp | 3 +--
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/TDB.cpp b/src/TDB.cpp
index c77febb7a..0ab4ed10a 100644
--- a/src/TDB.cpp
+++ b/src/TDB.cpp
@@ -398,6 +398,8 @@ bool TDB::readLockedFile (
}
////////////////////////////////////////////////////////////////////////////////
+// Scans the pending tasks for any that are completed or deleted, and if so,
+// moves them to the completed.data file. Returns a count of tasks moved.
int TDB::gc ()
{
int count = 0;
@@ -415,7 +417,9 @@ int TDB::gc ()
// Some tasks stay in the pending file.
if (it->getStatus () == T::pending ||
it->getStatus () == T::recurring)
+ {
pending.push_back (*it);
+ }
// Others are transferred to the completed file.
else
diff --git a/src/tests/tdb.t.cpp b/src/tests/tdb.t.cpp
index 3676f6517..c874c00fa 100644
--- a/src/tests/tdb.t.cpp
+++ b/src/tests/tdb.t.cpp
@@ -99,10 +99,9 @@ int main (int argc, char** argv)
// Add a new task.
T t2;
- t2.setId (2);
+ t2.setId (1);
t2.setAttribute ("project", "p2");
t2.setDescription ("task 2");
- t.diag (t2.compose ());
t.ok (tdb.addT (t2), "TDB::addT t2");
// Delete task.
From dac1942cad860e2cefb5a925a1372f78091858b6 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Tue, 10 Mar 2009 16:12:59 -0400
Subject: [PATCH 073/103] Bug Fix - calendar
- Task now displays as many calendars will fit across the window,
unless a lower value is specified in the "monthsperline" configuration
variable.
- Task now obeys the "color" configuration variable when determining
whether to add a legend to the calendar output.
---
html/config.html | 4 +++-
src/Config.cpp | 2 +-
src/report.cpp | 47 +++++++++++++++++++++++++++++++++--------------
3 files changed, 37 insertions(+), 16 deletions(-)
diff --git a/html/config.html b/html/config.html
index c614f3ad0..6fb09b51f 100644
--- a/html/config.html
+++ b/html/config.html
@@ -174,7 +174,9 @@
monthsperline
Determines how many months the "task calendar" command
- renders across the screen. Defaults to 1.
+ renders across the screen. Defaults to however many will
+ fit. If more months that will fit are specified, task will
+ only show as many that will fit.
oldest
diff --git a/src/Config.cpp b/src/Config.cpp
index 7ac95b1a7..48f549ea6 100644
--- a/src/Config.cpp
+++ b/src/Config.cpp
@@ -127,7 +127,7 @@ void Config::createDefault (const std::string& home)
fprintf (out, "confirmation=yes\n");
fprintf (out, "next=2\n");
fprintf (out, "dateformat=m/d/Y\n");
- fprintf (out, "monthsperline=2\n");
+ fprintf (out, "#monthsperline=2\n");
fprintf (out, "curses=on\n");
fprintf (out, "color=on\n");
fprintf (out, "due=7\n");
diff --git a/src/report.cpp b/src/report.cpp
index 6f25c90a4..d4e405723 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -1214,11 +1214,11 @@ std::string renderMonths (
int firstYear,
const Date& today,
std::vector & all,
- Config& conf)
+ Config& conf,
+ int monthsPerLine)
{
Table table;
table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
- int monthsPerLine = (conf.get ("monthsperline", 1));
// Build table for the number of months to be displayed.
for (int i = 0 ; i < (monthsPerLine * 8); i += 8)
@@ -1337,6 +1337,26 @@ std::string handleReportCalendar (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
+
+ // Each month requires 23 text columns width. See how many will actually
+ // fit. But if a preference is specified, and it fits, use it.
+ int preferredMonthsPerLine = (conf.get (std::string ("monthsperline"), 0));
+ int monthsThatFit = width / 23;
+
+ int monthsPerLine = monthsThatFit;
+ if (preferredMonthsPerLine != 0 && preferredMonthsPerLine < monthsThatFit)
+ monthsPerLine = preferredMonthsPerLine;
+
// Load all the pending tasks.
std::vector pending;
tdb.allPendingT (pending);
@@ -1369,8 +1389,6 @@ std::string handleReportCalendar (TDB& tdb, T& task, Config& conf)
out << std::endl;
std::string output;
- int monthsPerLine = (conf.get ("monthsperline", 1));
-
while (yFrom < yTo || (yFrom == yTo && mFrom <= mTo))
{
int nextM = mFrom;
@@ -1398,7 +1416,7 @@ std::string handleReportCalendar (TDB& tdb, T& task, Config& conf)
out << std::endl
<< optionalBlankLine (conf)
- << renderMonths (mFrom, yFrom, today, pending, conf)
+ << renderMonths (mFrom, yFrom, today, pending, conf, monthsPerLine)
<< std::endl;
mFrom += monthsPerLine;
@@ -1409,15 +1427,16 @@ std::string handleReportCalendar (TDB& tdb, T& task, Config& conf)
}
}
- out << "Legend: "
- << Text::colorize (Text::cyan, Text::nocolor, "today")
- << ", "
- << Text::colorize (Text::black, Text::on_yellow, "due")
- << ", "
- << Text::colorize (Text::black, Text::on_red, "overdue")
- << "."
- << optionalBlankLine (conf)
- << std::endl;
+ if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
+ out << "Legend: "
+ << Text::colorize (Text::cyan, Text::nocolor, "today")
+ << ", "
+ << Text::colorize (Text::black, Text::on_yellow, "due")
+ << ", "
+ << Text::colorize (Text::black, Text::on_red, "overdue")
+ << "."
+ << optionalBlankLine (conf)
+ << std::endl;
return out.str ();
}
From 1f45e47e367911f87863860fdb67f40c70050e7a Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Tue, 10 Mar 2009 16:37:35 -0400
Subject: [PATCH 074/103] Bug Fix - history/ghistory triggered only by add
- Fixed bug whereby if a new month rolls around, and no task is added,
no row of data is shown in the history or ghistory reports, even
though tasks may have been completed or deleted ni the new month.
---
src/report.cpp | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/src/report.cpp b/src/report.cpp
index d4e405723..c88633ba0 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -813,6 +813,7 @@ std::string handleReportHistory (TDB& tdb, T& task, Config& conf)
if (task.getStatus () == T::deleted)
{
epoch = monthlyEpoch (task.getAttribute ("end"));
+ groups[epoch] = 0;
if (deletedGroup.find (epoch) != deletedGroup.end ())
deletedGroup[epoch] = deletedGroup[epoch] + 1;
@@ -822,6 +823,7 @@ std::string handleReportHistory (TDB& tdb, T& task, Config& conf)
else if (task.getStatus () == T::completed)
{
epoch = monthlyEpoch (task.getAttribute ("end"));
+ groups[epoch] = 0;
if (completedGroup.find (epoch) != completedGroup.end ())
completedGroup[epoch] = completedGroup[epoch] + 1;
@@ -852,6 +854,7 @@ std::string handleReportHistory (TDB& tdb, T& task, Config& conf)
if (task.getStatus () == T::deleted)
{
epoch = monthlyEpoch (task.getAttribute ("end"));
+ groups[epoch] = 0;
if (deletedGroup.find (epoch) != deletedGroup.end ())
deletedGroup[epoch] = deletedGroup[epoch] + 1;
@@ -861,6 +864,8 @@ std::string handleReportHistory (TDB& tdb, T& task, Config& conf)
else if (task.getStatus () == T::completed)
{
epoch = monthlyEpoch (task.getAttribute ("end"));
+ groups[epoch] = 0;
+
if (completedGroup.find (epoch) != completedGroup.end ())
completedGroup[epoch] = completedGroup[epoch] + 1;
else
@@ -906,9 +911,9 @@ std::string handleReportHistory (TDB& tdb, T& task, Config& conf)
{
row = table.addRow ();
- totalAdded += addedGroup[i->first];
- totalCompleted += completedGroup[i->first];
- totalDeleted += deletedGroup[i->first];
+ totalAdded += addedGroup [i->first];
+ totalCompleted += completedGroup [i->first];
+ totalDeleted += deletedGroup [i->first];
Date dt (i->first);
int m, d, y;
From 2d07b08260773e7b974f10a2a694bec1ffc13ad1 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Tue, 10 Mar 2009 22:21:23 -0400
Subject: [PATCH 075/103] Custom Reports - usage
- Added defined custom reports to the usage text. This includes the
new "report.X.description" configuration variable.
---
html/custom.html | 12 +++++-----
src/parse.cpp | 7 +++++-
src/task.cpp | 38 ++++++++++++-------------------
src/task.h | 1 +
src/tests/custom.t | 56 ++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 84 insertions(+), 30 deletions(-)
create mode 100755 src/tests/custom.t
diff --git a/html/custom.html b/html/custom.html
index 8b202f5c1..a4a64c803 100644
--- a/html/custom.html
+++ b/html/custom.html
@@ -43,25 +43,27 @@
More importantly, you can define your own. Here are the
- two necessary items in the .taskrc file that define a new
+ three necessary items in the .taskrc file that define a new
report:
report.mine.description=Just the essentials
+report.mine.columns=id,project,priority,description
report.mine.sort=priority-,project+
This defines a report, called "mine", that has four columns:
id, project, priority and description. It will be sorted on
two columns: by descending priority then ascending project.
- Because this report is called "mine", it can be run with the
- command:
+ The description that shows up in the task command usage page
+ is "Just the essentials". Because this report is called
+ "mine", it can be run with the command:
% task mine
- A filter can also be specified like this:
+ An optional filter can also be specified like this:
report.mine.filter=priority:H +bug
diff --git a/src/parse.cpp b/src/parse.cpp
index d6528436c..b87ce8dc9 100644
--- a/src/parse.cpp
+++ b/src/parse.cpp
@@ -164,7 +164,6 @@ void guess (const std::string& type, const char** list, std::string& candidate)
candidate = matches[0];
else if (0 == matches.size ())
-// throw std::string ("Unrecognized ") + type + " '" + candidate + "'";
candidate = "";
else
@@ -535,4 +534,10 @@ bool isCustomReport (const std::string& report)
return false;
}
////////////////////////////////////////////////////////////////////////////////
+void allCustomReports (std::vector & all)
+{
+ all = customReports;
+}
+
+////////////////////////////////////////////////////////////////////////////////
diff --git a/src/task.cpp b/src/task.cpp
index 00b21d9cb..3c1b2f629 100644
--- a/src/task.cpp
+++ b/src/task.cpp
@@ -82,18 +82,6 @@ static void shortUsage (Config& conf)
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");
@@ -198,6 +186,20 @@ static void shortUsage (Config& conf)
table.addCell (row, 1, "task help");
table.addCell (row, 2, "Shows the long usage text");
+ // Add custom reports here...
+ std::vector all;
+ allCustomReports (all);
+ foreach (report, all)
+ {
+ std::string command = std::string ("task ") + *report + std::string (" [tags] [attrs] desc...");
+ std::string description = conf.get (
+ std::string ("report.") + *report + ".description", std::string ("(missing description)"));
+
+ row = table.addRow ();
+ table.addCell (row, 1, command);
+ table.addCell (row, 2, description);
+ }
+
std::cout << table.render ()
<< std::endl
<< "See http://www.beckingham.net/task.html for the latest releases and a full tutorial."
@@ -269,9 +271,6 @@ void loadConfFile (int argc, char** argv, Config& conf)
////////////////////////////////////////////////////////////////////////////////
int main (int argc, char** argv)
{
-// TODO Find out what this is, and either promote it to live code, or remove it.
-// std::set_terminate (__gnu_cxx::__verbose_terminate_handler);
-
// Set up randomness.
#ifdef HAVE_SRANDOM
srandom (time (NULL));
@@ -383,15 +382,6 @@ void nag (TDB& tdb, T& task, Config& conf)
}
// General form is "if there are no more deserving tasks", suppress the nag.
-/*
- std::cout << "# task.isOverdue = " << (isOverdue ? "true" : "false") << std::endl;
- std::cout << "# task.pri = " << pri << std::endl;
- std::cout << "# task.overdue = " << overdue << std::endl;
- std::cout << "# pending.high = " << high << std::endl;
- std::cout << "# pending.medium = " << medium << std::endl;
- std::cout << "# pending.low = " << low << std::endl;
-*/
-
if (isOverdue ) return;
if (pri == 'H' && !overdue ) return;
if (pri == 'M' && !overdue && !high ) return;
diff --git a/src/task.h b/src/task.h
index 925b75811..dffc3ef17 100644
--- a/src/task.h
+++ b/src/task.h
@@ -59,6 +59,7 @@ bool validPriority (const std::string&);
bool validDate (std::string&, Config&);
void loadCustomReports (Config&);
bool isCustomReport (const std::string&);
+void allCustomReports (std::vector &);
// task.cpp
void gatherNextTasks (const TDB&, T&, Config&, std::vector &, std::vector &);
diff --git a/src/tests/custom.t b/src/tests/custom.t
new file mode 100755
index 000000000..193e9711e
--- /dev/null
+++ b/src/tests/custom.t
@@ -0,0 +1,56 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 4;
+
+# Create the rc file.
+if (open my $fh, '>', 'custom.rc')
+{
+ print $fh "data.location=.\n",
+ "report.foo.description=DESC\n",
+ "report.foo.columns=id,description\n",
+ "report.foo.sort=id+\n";
+ close $fh;
+ ok (-r 'custom.rc', 'Created custom.rc');
+}
+
+# Generate the usage screen, and locate the custom report on it.
+my $output = qx{../task rc:custom.rc usage};
+like ($output, qr/task foo \[tags\] \[attrs\] desc\.\.\.\s+DESC\n/m, 'report.foo');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'custom.rc';
+ok (!-r 'custom.rc', 'Removed custom.rc');
+
+exit 0;
+
From 79d644c257139343811924ae3b707a0c994c53a2 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Tue, 10 Mar 2009 22:30:15 -0400
Subject: [PATCH 076/103] Unit Tests - custom
- Added unit tests to verify correct functioning of custom report
filters.
---
src/tests/custom.t | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/src/tests/custom.t b/src/tests/custom.t
index 193e9711e..5ca345aa0 100755
--- a/src/tests/custom.t
+++ b/src/tests/custom.t
@@ -28,7 +28,7 @@
use strict;
use warnings;
-use Test::More tests => 4;
+use Test::More tests => 6;
# Create the rc file.
if (open my $fh, '>', 'custom.rc')
@@ -36,7 +36,8 @@ if (open my $fh, '>', 'custom.rc')
print $fh "data.location=.\n",
"report.foo.description=DESC\n",
"report.foo.columns=id,description\n",
- "report.foo.sort=id+\n";
+ "report.foo.sort=id+\n",
+ "report.foo.filter=project:A\n";
close $fh;
ok (-r 'custom.rc', 'Created custom.rc');
}
@@ -45,6 +46,12 @@ if (open my $fh, '>', 'custom.rc')
my $output = qx{../task rc:custom.rc usage};
like ($output, qr/task foo \[tags\] \[attrs\] desc\.\.\.\s+DESC\n/m, 'report.foo');
+qx{../task rc:custom.rc add project:A one};
+qx{../task rc:custom.rc add two};
+$output = qx{../task rc:custom.rc foo};
+like ($output, qr/one/, 'custom filter included');
+unlike ($output, qr/two/, 'custom filter excluded');
+
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
From 8c95e82a63629419e718b1c39cb3a7052b2f5131 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Tue, 10 Mar 2009 23:06:02 -0400
Subject: [PATCH 077/103] Unit Tests - start/stop/acive
- Added unit tests to test the start and stop commands via the active
report.
---
src/tests/start.t | 73 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 73 insertions(+)
create mode 100755 src/tests/start.t
diff --git a/src/tests/start.t b/src/tests/start.t
new file mode 100755
index 000000000..20b7d92bc
--- /dev/null
+++ b/src/tests/start.t
@@ -0,0 +1,73 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 12;
+
+# Create the rc file.
+if (open my $fh, '>', 'start.rc')
+{
+ print $fh "data.location=.\n";
+ close $fh;
+ ok (-r 'start.rc', 'Created start.rc');
+}
+
+# Test the add/start/stop commands.
+qx{../task rc:start.rc add one};
+qx{../task rc:start.rc add two};
+my $output = qx{../task rc:start.rc active};
+unlike ($output, qr/one/, 'one not active');
+unlike ($output, qr/two/, 'two not active');
+
+qx{../task rc:start.rc start 1};
+qx{../task rc:start.rc start 2};
+$output = qx{../task rc:start.rc active};
+like ($output, qr/one/, 'one active');
+like ($output, qr/two/, 'two active');
+
+qx{../task rc:start.rc stop 1};
+$output = qx{../task rc:start.rc active};
+unlike ($output, qr/one/, 'one not active');
+like ($output, qr/two/, 'two active');
+
+qx{../task rc:start.rc stop 2};
+$output = qx{../task rc:start.rc active};
+unlike ($output, qr/one/, 'one not active');
+unlike ($output, qr/two/, 'two not active');
+
+# Cleanup.
+ok (-r 'pending.data', 'Need to remove pending.data');
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'start.rc';
+ok (!-r 'start.rc', 'Removed start.rc');
+
+exit 0;
+
From c35a76401935ed1acff71739be6f16a8d39c1e4f Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Thu, 12 Mar 2009 22:34:45 -0400
Subject: [PATCH 078/103] 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.
---
ChangeLog | 5 +-
html/config.html | 12 --
html/custom.html | 15 ++-
html/task.html | 3 +-
html/usage.html | 23 ++--
src/Config.cpp | 73 ++++++++----
src/Grid.cpp | 6 +-
src/Table.cpp | 10 +-
src/Table.h | 2 +-
src/command.cpp | 4 +-
src/parse.cpp | 5 -
src/report.cpp | 300 +----------------------------------------------
src/task.cpp | 10 --
src/task.h | 2 -
14 files changed, 101 insertions(+), 369 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index de3524351..7619471c7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/html/config.html b/html/config.html
index 6fb09b51f..bfe97b9ac 100644
--- a/html/config.html
+++ b/html/config.html
@@ -179,18 +179,6 @@
only show as many that will fit.
-
oldest
-
- Determines how many tasks the "task oldest" command displays.
- Defaults to 10.
-
-
-
newest
-
- Determines how many tasks the "task newest" command displays.
- Defaults to 10.
-
-
defaultwidth
The width of tables used when ncurses support is not available.
diff --git a/html/custom.html b/html/custom.html
index a4a64c803..1ee499a35 100644
--- a/html/custom.html
+++ b/html/custom.html
@@ -36,9 +36,10 @@
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.
@@ -74,6 +75,14 @@ report.mine.sort=priority-,project+
definition is optional.
+
+ 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.
+
+
+
report.mine.limit=10
+
Here is a list of all the possible columns that may be included
in a report:
diff --git a/html/task.html b/html/task.html
index 9f4ef60cc..956c26730 100644
--- a/html/task.html
+++ b/html/task.html
@@ -111,7 +111,8 @@
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
diff --git a/html/usage.html b/html/usage.html
index 9970427c6..840eb9b15 100644
--- a/html/usage.html
+++ b/html/usage.html
@@ -34,12 +34,10 @@
task add [tags] [attrs] desc...
- task list [tags] [attrs] desc...
- task long [tags] [attrs] desc...
- task ls [tags] [attrs] desc...
+
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:
- $ ! ' " ( ) ; \ ` * ? { } [ ] < > | & % # ~
+ $ ! ' " ( ) ; \ ` * ? { } [ ] < > | & % # ~
diff --git a/src/Config.cpp b/src/Config.cpp
index 48f549ea6..3476bc6f8 100644
--- a/src/Config.cpp
+++ b/src/Config.cpp
@@ -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.sort"] = "due+,priority-,project+";
- (*this)["report.list.columns"] = "id,project,priority,due,active,age,description";
- (*this)["report.list.sort"] = "due+,priority-,project+";
- (*this)["report.ls.columns"] = "id,project,priority,description";
- (*this)["report.ls.sort"] = "priority-,project+";
+ (*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, "# 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, "# 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, "# 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);
diff --git a/src/Grid.cpp b/src/Grid.cpp
index a391aa75b..bd1f0f6f5 100644
--- a/src/Grid.cpp
+++ b/src/Grid.cpp
@@ -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;
diff --git a/src/Table.cpp b/src/Table.cpp
index 071837cdf..8052ca0b3 100644
--- a/src/Table.cpp
+++ b/src/Table.cpp
@@ -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 > columns;
std::vector blanks;
diff --git a/src/Table.h b/src/Table.h
index fe098e896..aed5587e1 100644
--- a/src/Table.h
+++ b/src/Table.h
@@ -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);
diff --git a/src/command.cpp b/src/command.cpp
index 0a6e9756a..4197810ba 100644
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -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
diff --git a/src/parse.cpp b/src/parse.cpp
index b87ce8dc9..b0a1c5197 100644
--- a/src/parse.cpp
+++ b/src/parse.cpp
@@ -130,12 +130,7 @@ static const char* commands[] =
"history",
"ghistory",
"info",
- "list",
- "long",
- "ls",
- "newest",
"next",
- "oldest",
"overdue",
"projects",
"start",
diff --git a/src/report.cpp b/src/report.cpp
index c88633ba0..ff26b34c8 100644
--- a/src/report.cpp
+++ b/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 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 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")
diff --git a/src/task.cpp b/src/task.cpp
index 3c1b2f629..eacaaf7f7 100644
--- a/src/task.cpp
+++ b/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 ); }
diff --git a/src/task.h b/src/task.h
index dffc3ef17..05b710497 100644
--- a/src/task.h
+++ b/src/task.h
@@ -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 &);
From 05b5273136924505b52f24be75e6450414f4b034 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Thu, 12 Mar 2009 22:56:22 -0400
Subject: [PATCH 079/103] Unit Tests - oldest
- Implemented unit tests to verify that the "oldest" report does
indeed show the oldest 10 tasks.
- Implemented unit tests to verify that the "newest" report does
indeed show the newest 10 tasks.
---
src/tests/oldest.t | 89 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 89 insertions(+)
create mode 100755 src/tests/oldest.t
diff --git a/src/tests/oldest.t b/src/tests/oldest.t
new file mode 100755
index 000000000..395ed7adf
--- /dev/null
+++ b/src/tests/oldest.t
@@ -0,0 +1,89 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 25;
+
+# Create the rc file.
+if (open my $fh, '>', 'oldest.rc')
+{
+ print $fh "data.location=.\n";
+ close $fh;
+ ok (-r 'oldest.rc', 'Created oldest.rc');
+}
+
+# Add 11 tasks. Oldest should show 1-10, newest should show 2-11.
+diag ("Adding 11 tasks - takes 10 seconds");
+qx{../task rc:oldest.rc add one; sleep 1};
+qx{../task rc:oldest.rc add two; sleep 1};
+qx{../task rc:oldest.rc add three; sleep 1};
+qx{../task rc:oldest.rc add four; sleep 1};
+qx{../task rc:oldest.rc add five; sleep 1};
+qx{../task rc:oldest.rc add six; sleep 1};
+qx{../task rc:oldest.rc add seven; sleep 1};
+qx{../task rc:oldest.rc add eight; sleep 1};
+qx{../task rc:oldest.rc add nine; sleep 1};
+qx{../task rc:oldest.rc add ten; sleep 1};
+qx{../task rc:oldest.rc add eleven};
+
+my $output = qx{../task rc:oldest.rc oldest};
+like ($output, qr/one/, 'oldest: one');
+like ($output, qr/two/, 'oldest: two');
+like ($output, qr/three/, 'oldest: three');
+like ($output, qr/four/, 'oldest: four');
+like ($output, qr/five/, 'oldest: five');
+like ($output, qr/six/, 'oldest: six');
+like ($output, qr/seven/, 'oldest: seven');
+like ($output, qr/eight/, 'oldest: eight');
+like ($output, qr/nine/, 'oldest: nine');
+like ($output, qr/ten/, 'oldest: ten');
+unlike ($output, qr/eleven/, 'no: eleven');
+
+$output = qx{../task rc:oldest.rc newest};
+unlike ($output, qr/one/, 'no: one');
+like ($output, qr/two/, 'newest: two');
+like ($output, qr/three/, 'newest: three');
+like ($output, qr/four/, 'newest: four');
+like ($output, qr/five/, 'newest: five');
+like ($output, qr/six/, 'newest: six');
+like ($output, qr/seven/, 'newest: seven');
+like ($output, qr/eight/, 'newest: eight');
+like ($output, qr/nine/, 'newest: nine');
+like ($output, qr/ten/, 'newest: ten');
+like ($output, qr/eleven/, 'newest: eleven');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'oldest.rc';
+ok (!-r 'oldest.rc', 'Removed oldest.rc');
+
+exit 0;
+
From 0cfc9c720e21b3d7d550e8e79e3318a5d602c339 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Fri, 13 Mar 2009 09:06:23 -0400
Subject: [PATCH 080/103] Compile Bug - missing
- Added stdlib.h to Grid.cpp, thanks to Benjamin Tegardin.
---
AUTHORS | 1 +
src/Grid.cpp | 1 +
2 files changed, 2 insertions(+)
diff --git a/AUTHORS b/AUTHORS
index 7fcc9c14b..825c87b96 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -24,4 +24,5 @@ With thanks to:
Russell Friesenhahn
Paolo Marsi
Eric Farris
+ Benjamin Tegarden
diff --git a/src/Grid.cpp b/src/Grid.cpp
index bd1f0f6f5..59e366b32 100644
--- a/src/Grid.cpp
+++ b/src/Grid.cpp
@@ -60,6 +60,7 @@
////////////////////////////////////////////////////////////////////////////////
#include
+#include
#include
////////////////////////////////////////////////////////////////////////////////
From 28c97f181a6e6a3820a52a6c15a806c72bbe3f2d Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Fri, 13 Mar 2009 10:35:17 -0400
Subject: [PATCH 081/103] Grammar
- Changed wording of the help output.
---
src/command.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/command.cpp b/src/command.cpp
index 4197810ba..769fa4af1 100644
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -309,7 +309,7 @@ std::string handleVersion (Config& conf)
link.addCell (link.addRow (), 0,
"See http://www.beckingham.net/task.html for the latest releases and a "
"full tutorial. New releases containing fixes and enhancements are "
- "released frequently.");
+ "made frequently.");
// Create a table for output.
Table table;
From 2216eee67809f567bf9c3d41d27c8f2b8f322a32 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Fri, 13 Mar 2009 13:12:34 -0400
Subject: [PATCH 082/103] Help Consistency
- Added note about frequent releases to the shortUsage output, so it
is now consistent with that of "version".
---
src/task.cpp | 56 +++++++++++++++++++++++++++-------------------------
1 file changed, 29 insertions(+), 27 deletions(-)
diff --git a/src/task.cpp b/src/task.cpp
index eacaaf7f7..4c958684d 100644
--- a/src/task.cpp
+++ b/src/task.cpp
@@ -194,7 +194,9 @@ static void shortUsage (Config& conf)
std::cout << table.render ()
<< std::endl
- << "See http://www.beckingham.net/task.html for the latest releases and a full tutorial."
+ << "See http://www.beckingham.net/task.html for the latest releases and a "
+ << "full tutorial. New releases containing fixes and enhancements are "
+ << "made frequently."
<< std::endl
<< std::endl;
}
@@ -205,32 +207,32 @@ static void longUsage (Config& conf)
shortUsage (conf);
std::cout
- << "ID is the numeric identifier displayed by the 'task list' command" << "\n"
- << "\n"
- << "Tags are arbitrary words, any quantity:" << "\n"
- << " +tag The + means add the tag" << "\n"
- << " -tag The - means remove the tag" << "\n"
- << "\n"
- << "Attributes are:" << "\n"
- << " project: Project name" << "\n"
- << " priority: Priority" << "\n"
- << " due: Due date" << "\n"
- << " recur: Recurrence frequency" << "\n"
- << " until: Recurrence end date" << "\n"
- << " fg: Foreground color" << "\n"
- << " bg: Background color" << "\n"
- << " rc: Alternate .taskrc file" << "\n"
- << "\n"
- << "Any command or attribute name may be abbreviated if still unique:" << "\n"
- << " task list project:Home" << "\n"
- << " task li pro:Home" << "\n"
- << "\n"
- << "Some task descriptions need to be escaped because of the shell:" << "\n"
- << " task add \"quoted ' quote\"" << "\n"
- << " task add escaped \\' quote" << "\n"
- << "\n"
- << "Many characters have special meaning to the shell, including:" << "\n"
- << " $ ! ' \" ( ) ; \\ ` * ? { } [ ] < > | & % # ~" << "\n"
+ << "ID is the numeric identifier displayed by the 'task list' command." << "\n"
+ << "\n"
+ << "Tags are arbitrary words, any quantity:" << "\n"
+ << " +tag The + means add the tag" << "\n"
+ << " -tag The - means remove the tag" << "\n"
+ << "\n"
+ << "Attributes are:" << "\n"
+ << " project: Project name" << "\n"
+ << " priority: Priority" << "\n"
+ << " due: Due date" << "\n"
+ << " recur: Recurrence frequency" << "\n"
+ << " until: Recurrence end date" << "\n"
+ << " fg: Foreground color" << "\n"
+ << " bg: Background color" << "\n"
+ << " rc: Alternate .taskrc file" << "\n"
+ << "\n"
+ << "Any command or attribute name may be abbreviated if still unique:" << "\n"
+ << " task list project:Home" << "\n"
+ << " task li pro:Home" << "\n"
+ << "\n"
+ << "Some task descriptions need to be escaped because of the shell:" << "\n"
+ << " task add \"quoted ' quote\"" << "\n"
+ << " task add escaped \\' quote" << "\n"
+ << "\n"
+ << "Many characters have special meaning to the shell, including:" << "\n"
+ << " $ ! ' \" ( ) ; \\ ` * ? { } [ ] < > | & % # ~" << "\n"
<< std::endl;
}
From 4a524a220e26ba34050d7f667e08eb7900daae60 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sat, 14 Mar 2009 00:21:42 -0400
Subject: [PATCH 083/103] Bug Fix - default command, default unit test
- Task runs the default command when no arguments are provided, but
when an "rc:..." argument is provided, it does not run the default
command.
- Implemented unit tests to verify the functioning of default commands,
default project and default priority.
---
src/task.cpp | 4 ++-
src/tests/default.t | 83 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 86 insertions(+), 1 deletion(-)
create mode 100755 src/tests/default.t
diff --git a/src/task.cpp b/src/task.cpp
index 4c958684d..132879e4c 100644
--- a/src/task.cpp
+++ b/src/task.cpp
@@ -774,7 +774,9 @@ std::string runTaskCommand (
// If argc == 1 and the default.command configuration variable is set,
// then use that, otherwise stick with argc/argv.
std::string defaultCommand = conf.get ("default.command");
- if (args.size () == 0 && defaultCommand != "")
+ if ((args.size () == 0 ||
+ (args.size () == 1 && args[0].substr (0, 3) == "rc:")) &&
+ defaultCommand != "")
{
// Stuff the command line.
args.clear ();
diff --git a/src/tests/default.t b/src/tests/default.t
new file mode 100755
index 000000000..6851b0063
--- /dev/null
+++ b/src/tests/default.t
@@ -0,0 +1,83 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 16;
+
+# Create the rc file.
+if (open my $fh, '>', 'default.rc')
+{
+ print $fh "data.location=.\n",
+ "default.command=list\n",
+ "default.project=PROJECT\n",
+ "default.priority=M\n";
+ close $fh;
+ ok (-r 'default.rc', 'Created default.rc');
+}
+
+# Set up a default command, project and priority.
+qx{../task rc:default.rc add all defaults};
+my $output = qx{../task rc:default.rc list};
+like ($output, qr/ all defaults/, 'task added');
+like ($output, qr/ PROJECT /, 'default project added');
+like ($output, qr/ M /, 'default priority added');
+unlink 'pending.data';
+
+qx{../task rc:default.rc add project:specific priority:L all specified};
+$output = qx{../task rc:default.rc list};
+like ($output, qr/ all specified/, 'task added');
+like ($output, qr/ specific /, 'project specified');
+like ($output, qr/ L /, 'priority specified');
+unlink 'pending.data';
+
+qx{../task rc:default.rc add project:specific project specified};
+$output = qx{../task rc:default.rc list};
+like ($output, qr/ project specified/, 'task added');
+like ($output, qr/ specific /, 'project specified');
+like ($output, qr/ M /, 'default priority added');
+unlink 'pending.data';
+
+qx{../task rc:default.rc add priority:L priority specified};
+$output = qx{../task rc:default.rc list};
+like ($output, qr/ priority specified/, 'task added');
+like ($output, qr/ PROJECT /, 'default project added');
+like ($output, qr/ L /, 'priority specified');
+
+$output = qx{../task rc:default.rc};
+like ($output, qr/1 PROJECT L .+ priority specified/, 'default command worked');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'default.rc';
+ok (!-r 'default.rc', 'Removed default.rc');
+
+exit 0;
+
From 7c87bbc19ae1f729189ebb4f3fb46a5ece463a23 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sat, 14 Mar 2009 12:02:33 -0400
Subject: [PATCH 084/103] Unit Tests - dateformat
- Unit tests determine whether the dateformat configuration variable
determines how dates are parsed, and how dates are rendered.
---
src/tests/dateformat.t | 54 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
create mode 100755 src/tests/dateformat.t
diff --git a/src/tests/dateformat.t b/src/tests/dateformat.t
new file mode 100755
index 000000000..83fe0b293
--- /dev/null
+++ b/src/tests/dateformat.t
@@ -0,0 +1,54 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 5;
+
+# Create the rc file.
+if (open my $fh, '>', 'date.rc')
+{
+ print $fh "data.location=.\n",
+ "dateformat=YMD\n";
+ close $fh;
+ ok (-r 'date.rc', 'Created date.rc');
+}
+
+qx{../task rc:date.rc add foo due:20091231};
+my $output = qx{../task rc:date.rc info 1};
+like ($output, qr/\b20091231\b/, 'date format YMD parsed');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'date.rc';
+ok (!-r 'date.rc', 'Removed date.rc');
+
+exit 0;
+
From 64cfc26ff3c3dd149f21fceec4fd90cc7dcca55b Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sat, 14 Mar 2009 12:04:25 -0400
Subject: [PATCH 085/103] Enhanced Stats Report
- now reports number of unique tags (given filtering)
- now reports number of unique projects (given filtering)
---
src/report.cpp | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/src/report.cpp b/src/report.cpp
index ff26b34c8..5820bd7c5 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -1699,6 +1699,8 @@ std::string handleReportStats (TDB& tdb, T& task, Config& conf)
int recurringT = 0;
float daysPending = 0.0;
int descLength = 0;
+ std::map allTags;
+ std::map allProjects;
std::vector ::iterator it;
for (it = tasks.begin (); it != tasks.end (); ++it)
@@ -1727,6 +1729,13 @@ std::string handleReportStats (TDB& tdb, T& task, Config& conf)
std::vector tags;
it->getTags (tags);
if (tags.size ()) ++taggedT;
+
+ foreach (t, tags)
+ allTags[*t] = 0;
+
+ std::string project = it->getAttribute ("project");
+ if (project != "")
+ allProjects[project] = 0;
}
out << "Pending " << pendingT << std::endl
@@ -1764,6 +1773,9 @@ std::string handleReportStats (TDB& tdb, T& task, Config& conf)
out << "Tasks tagged " << std::setprecision (3) << (100.0 * taggedT / totalT) << "%" << std::endl;
}
+ out << "Unique tags " << allTags.size () << std::endl;
+ out << "Projects " << allProjects.size () << std::endl;
+
return out.str ();
}
From c9a6d2a7504f0c1985c70e679fd44c25c2f11528 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sat, 14 Mar 2009 12:05:32 -0400
Subject: [PATCH 086/103] Improved GC and Shadow File Handling
- Every command now returns an output string, or at least has an
opportunity to do so.
- TDB::gc is only performed a) when allowed, and b) when the command
will display line numbers.
- updateShadowFile is only performed when a) shadow updates are allowed,
and either b) when a command is guaranteed to have modified a task or
c) when TDB:gc has already made changes.
---
src/command.cpp | 23 ++++++--
src/task.cpp | 150 +++++++++++++++++++++++++++---------------------
src/task.h | 8 +--
3 files changed, 107 insertions(+), 74 deletions(-)
diff --git a/src/command.cpp b/src/command.cpp
index 769fa4af1..16740bf59 100644
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -48,8 +48,10 @@
#endif
////////////////////////////////////////////////////////////////////////////////
-void handleAdd (TDB& tdb, T& task, Config& conf)
+std::string handleAdd (TDB& tdb, T& task, Config& conf)
{
+ std::stringstream out;
+
char entryTime[16];
sprintf (entryTime, "%u", (unsigned int) time (NULL));
task.setAttribute ("entry", entryTime);
@@ -86,6 +88,8 @@ void handleAdd (TDB& tdb, T& task, Config& conf)
if (!tdb.addT (task))
throw std::string ("Could not create new task.");
+
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
@@ -547,8 +551,10 @@ std::string handleStop (TDB& tdb, T& task, Config& conf)
}
////////////////////////////////////////////////////////////////////////////////
-void handleDone (TDB& tdb, T& task, Config& conf)
+std::string handleDone (TDB& tdb, T& task, Config& conf)
{
+ std::stringstream out;
+
if (!tdb.completeT (task))
throw std::string ("Could not mark task as completed.");
@@ -566,11 +572,14 @@ void handleDone (TDB& tdb, T& task, Config& conf)
}
nag (tdb, task, conf);
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
-void handleExport (TDB& tdb, T& task, Config& conf)
+std::string handleExport (TDB& tdb, T& task, Config& conf)
{
+ std::stringstream out;
+
// Use the description as a file name, then clobber the description so the
// file name isn't used for filtering.
std::string file = trim (task.getDescription ());
@@ -610,11 +619,14 @@ void handleExport (TDB& tdb, T& task, Config& conf)
}
else
throw std::string ("You must specify a file to write to.");
+
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
-void handleModify (TDB& tdb, T& task, Config& conf)
+std::string handleModify (TDB& tdb, T& task, Config& conf)
{
+ std::stringstream out;
std::vector all;
tdb.pendingT (all);
@@ -695,11 +707,12 @@ void handleModify (TDB& tdb, T& task, Config& conf)
tdb.modifyT (original);
}
- return;
+ return out.str ();
}
}
throw std::string ("Task not found.");
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/src/task.cpp b/src/task.cpp
index 132879e4c..d31952f02 100644
--- a/src/task.cpp
+++ b/src/task.cpp
@@ -27,6 +27,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -47,8 +48,9 @@
#endif
////////////////////////////////////////////////////////////////////////////////
-static void shortUsage (Config& conf)
+static std::string shortUsage (Config& conf)
{
+ std::stringstream out;
Table table;
int width = conf.get ("defaultwidth", 80);
#ifdef HAVE_LIBNCURSES
@@ -192,48 +194,51 @@ static void shortUsage (Config& conf)
table.addCell (row, 2, description);
}
- std::cout << table.render ()
- << std::endl
- << "See http://www.beckingham.net/task.html for the latest releases and a "
- << "full tutorial. New releases containing fixes and enhancements are "
- << "made frequently."
- << std::endl
- << std::endl;
+ out << table.render ()
+ << std::endl
+ << "See http://www.beckingham.net/task.html for the latest releases and a "
+ << "full tutorial. New releases containing fixes and enhancements are "
+ << "made frequently."
+ << std::endl
+ << std::endl;
+
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
-static void longUsage (Config& conf)
+static std::string longUsage (Config& conf)
{
- shortUsage (conf);
+ std::stringstream out;
+ out << shortUsage (conf)
+ << "ID is the numeric identifier displayed by the 'task list' command." << "\n"
+ << "\n"
+ << "Tags are arbitrary words, any quantity:" << "\n"
+ << " +tag The + means add the tag" << "\n"
+ << " -tag The - means remove the tag" << "\n"
+ << "\n"
+ << "Attributes are:" << "\n"
+ << " project: Project name" << "\n"
+ << " priority: Priority" << "\n"
+ << " due: Due date" << "\n"
+ << " recur: Recurrence frequency" << "\n"
+ << " until: Recurrence end date" << "\n"
+ << " fg: Foreground color" << "\n"
+ << " bg: Background color" << "\n"
+ << " rc: Alternate .taskrc file" << "\n"
+ << "\n"
+ << "Any command or attribute name may be abbreviated if still unique:" << "\n"
+ << " task list project:Home" << "\n"
+ << " task li pro:Home" << "\n"
+ << "\n"
+ << "Some task descriptions need to be escaped because of the shell:" << "\n"
+ << " task add \"quoted ' quote\"" << "\n"
+ << " task add escaped \\' quote" << "\n"
+ << "\n"
+ << "Many characters have special meaning to the shell, including:" << "\n"
+ << " $ ! ' \" ( ) ; \\ ` * ? { } [ ] < > | & % # ~" << "\n"
+ << std::endl;
- std::cout
- << "ID is the numeric identifier displayed by the 'task list' command." << "\n"
- << "\n"
- << "Tags are arbitrary words, any quantity:" << "\n"
- << " +tag The + means add the tag" << "\n"
- << " -tag The - means remove the tag" << "\n"
- << "\n"
- << "Attributes are:" << "\n"
- << " project: Project name" << "\n"
- << " priority: Priority" << "\n"
- << " due: Due date" << "\n"
- << " recur: Recurrence frequency" << "\n"
- << " until: Recurrence end date" << "\n"
- << " fg: Foreground color" << "\n"
- << " bg: Background color" << "\n"
- << " rc: Alternate .taskrc file" << "\n"
- << "\n"
- << "Any command or attribute name may be abbreviated if still unique:" << "\n"
- << " task list project:Home" << "\n"
- << " task li pro:Home" << "\n"
- << "\n"
- << "Some task descriptions need to be escaped because of the shell:" << "\n"
- << " task add \"quoted ' quote\"" << "\n"
- << " task add escaped \\' quote" << "\n"
- << "\n"
- << "Many characters have special meaning to the shell, including:" << "\n"
- << " $ ! ' \" ( ) ; \\ ` * ? { } [ ] < > | & % # ~" << "\n"
- << std::endl;
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
@@ -790,34 +795,49 @@ std::string runTaskCommand (
T task;
parse (args, command, task, conf);
- std::string out = "";
+ bool gcMod = false; // Change occurred by way of gc.
+ bool cmdMod = false; // Change occurred by way of command type.
+ std::string out;
- if (command == "" && task.getId ()) { handleModify (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); }
- else if (command == "add") { handleAdd (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); }
- else if (command == "done") { handleDone (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); }
- else if (command == "export") { handleExport (tdb, task, conf ); }
- else if (command == "projects") { out = handleProjects (tdb, task, conf ); }
- else if (command == "tags") { out = handleTags (tdb, task, conf ); }
- else if (command == "info") { out = handleInfo (tdb, task, conf ); }
- else if (command == "undelete") { out = handleUndelete (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); }
- else if (command == "delete") { out = handleDelete (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); }
- else if (command == "start") { out = handleStart (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); }
- else if (command == "stop") { out = handleStop (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); }
- else if (command == "undo") { out = handleUndo (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); }
- else if (command == "stats") { out = handleReportStats (tdb, task, conf ); }
- else if (command == "completed") { if (gc) tdb.gc (); out = handleCompleted (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } // TODO replace with Custom
- else if (command == "summary") { if (gc) tdb.gc (); out = handleReportSummary (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); }
- else if (command == "next") { if (gc) tdb.gc (); out = handleReportNext (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } // TODO replace with Custom
- else if (command == "history") { if (gc) tdb.gc (); out = handleReportHistory (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); }
- else if (command == "ghistory") { if (gc) tdb.gc (); out = handleReportGHistory (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 == "overdue") { if (gc) tdb.gc (); out = handleReportOverdue (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 ); }
- else if (isCustomReport (command)) { if (gc) tdb.gc (); out = handleCustomReport (tdb, task, conf, command); if (shadow) updateShadowFile (tdb, conf); } // New Custom reports
- else { shortUsage ( conf ); }
+ // Read-only commands with no side effects.
+ if (command == "export") { out = handleExport (tdb, task, conf); }
+ else if (command == "projects") { out = handleProjects (tdb, task, conf); }
+ else if (command == "tags") { out = handleTags (tdb, task, conf); }
+ else if (command == "info") { out = handleInfo (tdb, task, conf); }
+ else if (command == "stats") { out = handleReportStats (tdb, task, conf); }
+ else if (command == "history") { out = handleReportHistory (tdb, task, conf); }
+ else if (command == "ghistory") { out = handleReportGHistory (tdb, task, conf); }
+ else if (command == "calendar") { out = handleReportCalendar (tdb, task, conf); }
+ else if (command == "summary") { out = handleReportSummary (tdb, task, conf); }
+ else if (command == "colors") { out = handleColor ( conf); }
+ else if (command == "version") { out = handleVersion ( conf); }
+ else if (command == "help") { out = longUsage ( conf); }
+
+ // Commands that cause updates.
+ else if (command == "" && task.getId ()) { cmdMod = true; out = handleModify (tdb, task, conf); }
+ else if (command == "add") { cmdMod = true; out = handleAdd (tdb, task, conf); }
+ else if (command == "done") { cmdMod = true; out = handleDone (tdb, task, conf); }
+ else if (command == "undelete") { cmdMod = true; out = handleUndelete (tdb, task, conf); }
+ else if (command == "delete") { cmdMod = true; out = handleDelete (tdb, task, conf); }
+ else if (command == "start") { cmdMod = true; out = handleStart (tdb, task, conf); }
+ else if (command == "stop") { cmdMod = true; out = handleStop (tdb, task, conf); }
+ else if (command == "undo") { cmdMod = true; out = handleUndo (tdb, task, conf); }
+
+ // Command that display IDs and therefore need TDB::gc first.
+
+ else if (command == "completed") { if (gc) gcMod = tdb.gc (); out = handleCompleted (tdb, task, conf); }
+ else if (command == "next") { if (gc) gcMod = tdb.gc (); out = handleReportNext (tdb, task, conf); }
+ else if (command == "active") { if (gc) gcMod = tdb.gc (); out = handleReportActive (tdb, task, conf); }
+ else if (command == "overdue") { if (gc) gcMod = tdb.gc (); out = handleReportOverdue (tdb, task, conf); }
+ else if (isCustomReport (command)) { if (gc) gcMod = tdb.gc (); out = handleCustomReport (tdb, task, conf, command); }
+
+ // If the command is not recognized, display usage.
+ else { out = shortUsage (conf); }
+
+ // Only update the shadow file if such an update was not suppressed (shadow),
+ // and if an actual change occurred (gcMod || cmdMod).
+ if (shadow && (gcMod || cmdMod))
+ updateShadowFile (tdb, conf);
return out;
}
diff --git a/src/task.h b/src/task.h
index 05b710497..5ddd81f6f 100644
--- a/src/task.h
+++ b/src/task.h
@@ -74,10 +74,10 @@ std::string runTaskCommand (int, char**, TDB&, Config&, bool gc = true, bool sha
std::string runTaskCommand (std::vector &, TDB&, Config&, bool gc = false, bool shadow = false);
// command.cpp
-void handleAdd (TDB&, T&, Config&);
-void handleExport (TDB&, T&, Config&);
-void handleDone (TDB&, T&, Config&);
-void handleModify (TDB&, T&, Config&);
+std::string handleAdd (TDB&, T&, Config&);
+std::string handleExport (TDB&, T&, Config&);
+std::string handleDone (TDB&, T&, Config&);
+std::string handleModify (TDB&, T&, Config&);
std::string handleProjects (TDB&, T&, Config&);
std::string handleTags (TDB&, T&, Config&);
std::string handleUndelete (TDB&, T&, Config&);
From 8ac3978222e05e3ab09e01dcb59506bfb1912ec5 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sat, 14 Mar 2009 12:54:11 -0400
Subject: [PATCH 087/103] Unit Tests - dateformat, shadow
- Improved dateformat.t tests to cover all acceptable date format
characters.
- Unit tests for shadow file update notification.
- Unit tests for shadow file updates under certain circumstances.
- Unit tests for shadow file no updates under other circumstances.
---
src/tests/dateformat.t | 32 ++++++++++---
src/tests/shadow.t | 101 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 126 insertions(+), 7 deletions(-)
create mode 100755 src/tests/shadow.t
diff --git a/src/tests/dateformat.t b/src/tests/dateformat.t
index 83fe0b293..c08cdb884 100755
--- a/src/tests/dateformat.t
+++ b/src/tests/dateformat.t
@@ -28,27 +28,45 @@
use strict;
use warnings;
-use Test::More tests => 5;
+use Test::More tests => 8;
# Create the rc file.
-if (open my $fh, '>', 'date.rc')
+if (open my $fh, '>', 'date1.rc')
{
print $fh "data.location=.\n",
"dateformat=YMD\n";
close $fh;
- ok (-r 'date.rc', 'Created date.rc');
+ ok (-r 'date1.rc', 'Created date1.rc');
}
-qx{../task rc:date.rc add foo due:20091231};
-my $output = qx{../task rc:date.rc info 1};
+if (open my $fh, '>', 'date2.rc')
+{
+ print $fh "data.location=.\n",
+ "dateformat=m/d/y\n";
+ close $fh;
+ ok (-r 'date2.rc', 'Created date2.rc');
+}
+
+qx{../task rc:date1.rc add foo due:20091231};
+my $output = qx{../task rc:date1.rc info 1};
like ($output, qr/\b20091231\b/, 'date format YMD parsed');
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+qx{../task rc:date2.rc add foo due:12/1/09};
+$output = qx{../task rc:date2.rc info 1};
+like ($output, qr/\b12\/1\/09\b/, 'date format m/d/y parsed');
+
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
-unlink 'date.rc';
-ok (!-r 'date.rc', 'Removed date.rc');
+unlink 'date1.rc';
+ok (!-r 'date1.rc', 'Removed date1.rc');
+
+unlink 'date2.rc';
+ok (!-r 'date2.rc', 'Removed date2.rc');
exit 0;
diff --git a/src/tests/shadow.t b/src/tests/shadow.t
new file mode 100755
index 000000000..abea89205
--- /dev/null
+++ b/src/tests/shadow.t
@@ -0,0 +1,101 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 21;
+
+# Create the rc file.
+if (open my $fh, '>', 'shadow.rc')
+{
+ print $fh "data.location=.\n",
+ "shadow.file=./shadow.txt\n",
+ "shadow.command=stats\n",
+ "shadow.notify=on\n";
+ close $fh;
+ ok (-r 'shadow.rc', 'Created shadow.rc');
+}
+
+my $output = qx{../task rc:shadow.rc add one};
+like ($output, qr/\[Shadow file '\.\/shadow\.txt' updated\]/, 'shadow file updated on add');
+
+$output = qx{../task rc:shadow.rc list};
+unlike ($output, qr/\[Shadow file '\.\/shadow\.txt' updated\]/, 'shadow file not updated on list');
+
+$output = qx{../task rc:shadow.rc delete 1};
+like ($output, qr/\[Shadow file '\.\/shadow\.txt' updated\]/, 'shadow file updated on delete');
+
+$output = qx{../task rc:shadow.rc list};
+like ($output, qr/\[Shadow file '\.\/shadow\.txt' updated\]/, 'shadow file updated on list');
+
+# Inspect the shadow file.
+my $file = slurp ('./shadow.txt');
+like ($file, qr/Pending\s+0\n/, 'Pending 0');
+like ($file, qr/Recurring\s+0\n/, 'Recurring 0');
+like ($file, qr/Completed\s+0\n/, 'Completed 0');
+like ($file, qr/Deleted\s+1\n/, 'Deleted 1');
+like ($file, qr/Total\s+1\n/, 'Total 1');
+like ($file, qr/Task used for\s+-\n/, 'Task used for -');
+like ($file, qr/Task added every\s+-\n/, 'Task added every -');
+like ($file, qr/Task deleted every\s+-\n/, 'Task deleted every -');
+like ($file, qr/Average desc length\s+3 characters\n/, 'Average desc length 3 characters');
+like ($file, qr/Tasks tagged\s+0%\n/, 'Tasks tagged 0%');
+like ($file, qr/Unique tags\s+0\n/, 'Unique tags 0');
+like ($file, qr/Projects\s+0\n/, 'Projects 0');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'completed.data';
+ok (!-r 'completed.data', 'Removed completed.data');
+
+unlink 'shadow.rc';
+ok (!-r 'shadow.rc', 'Removed shadow.rc');
+
+unlink 'shadow.txt';
+ok (!-r 'shadow.txt', 'Removed shadow.txt');
+
+exit 0;
+
+################################################################################
+sub slurp
+{
+ my ($file) = @_;
+ local $/;
+
+ if (open my $fh, '<', $file)
+ {
+ my $contents = <$fh>;
+ close $fh;
+ return $contents;
+ }
+
+ '';
+}
+
From 5383943fa72f4f110a743bbd931ab5ec36ee094c Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sat, 14 Mar 2009 13:36:32 -0400
Subject: [PATCH 088/103] Enhanced export command
- Now sanitizes output by replacing ' with " in descriptions.
- Added 'recur' attribute to exported output.
- Removed recurring, deleted and complete tasks from the export.
---
src/T.cpp | 11 ++++++++++-
src/command.cpp | 17 +++++++++++++----
src/util.cpp | 1 +
3 files changed, 24 insertions(+), 5 deletions(-)
diff --git a/src/T.cpp b/src/T.cpp
index 61acd52f4..f490d8681 100644
--- a/src/T.cpp
+++ b/src/T.cpp
@@ -328,6 +328,11 @@ const std::string T::composeCSV ()
line += value;
line += ",";
+ value = mAttributes["recur"];
+ if (value != "")
+ line += value;
+ line += ",";
+
value = mAttributes["end"];
if (value != "")
line += value;
@@ -353,7 +358,11 @@ const std::string T::composeCSV ()
line += "'" + value + "'";
line += ",";
- line += "'" + mDescription + "'\n";
+ // Convert single quotes to double quotes, because single quotes are used to
+ // delimit the values that need it.
+ std::string clean = mDescription;
+ std::replace (clean.begin (), clean.end (), '\'', '"');
+ line += "'" + clean + "'\n";
return line;
}
diff --git a/src/command.cpp b/src/command.cpp
index 16740bf59..72724f668 100644
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -578,7 +578,7 @@ std::string handleDone (TDB& tdb, T& task, Config& conf)
////////////////////////////////////////////////////////////////////////////////
std::string handleExport (TDB& tdb, T& task, Config& conf)
{
- std::stringstream out;
+ std::stringstream output;
// Use the description as a file name, then clobber the description so the
// file name isn't used for filtering.
@@ -597,6 +597,7 @@ std::string handleExport (TDB& tdb, T& task, Config& conf)
<< "'entry',"
<< "'start',"
<< "'due',"
+ << "'recur',"
<< "'end',"
<< "'project',"
<< "'priority',"
@@ -605,14 +606,22 @@ std::string handleExport (TDB& tdb, T& task, Config& conf)
<< "'description'"
<< "\n";
+ int count = 0;
std::vector all;
- tdb.allT (all);
+ tdb.allPendingT (all);
filter (all, task);
foreach (t, all)
{
- out << t->composeCSV ().c_str ();
+ if (t->getStatus () != T::recurring &&
+ t->getStatus () != T::deleted)
+ {
+ out << t->composeCSV ().c_str ();
+ ++count;
+ }
}
out.close ();
+
+ output << count << " tasks exported to '" << file << "'" << std::endl;
}
else
throw std::string ("Could not write to export file.");
@@ -620,7 +629,7 @@ std::string handleExport (TDB& tdb, T& task, Config& conf)
else
throw std::string ("You must specify a file to write to.");
- return out.str ();
+ return output.str ();
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/src/util.cpp b/src/util.cpp
index 7f1e6b911..a114c9a0b 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -187,6 +187,7 @@ static char randomHexDigit ()
{
static char digits[] = "0123456789abcdef";
#ifdef HAVE_RANDOM
+ // random is better than rand.
return digits[random () % 16];
#else
return digits[rand () % 16];
From bdd1b16ba0bf255d55a87a980c72a6a27d1af784 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sat, 14 Mar 2009 13:38:39 -0400
Subject: [PATCH 089/103] Documentation Update
- Updated docs to reflect recent changes.
---
ChangeLog | 2 ++
html/task.html | 2 ++
2 files changed, 4 insertions(+)
diff --git a/ChangeLog b/ChangeLog
index 7619471c7..1a0f7a89b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -36,6 +36,8 @@
specifies the color of recurring tasks.
+ Added support for "locking" configuration variable that controls whether
file locking is used.
+ + Task export feature now includes recurrence information, removes nested
+ quotes, and limits output to pending tasks.
------ old releases ------------------------------
diff --git a/html/task.html b/html/task.html
index 956c26730..fa0f4ded2 100644
--- a/html/task.html
+++ b/html/task.html
@@ -130,6 +130,8 @@
specifies the color of recurring tasks.
Added support for "locking" configuration variable that controls whether
file locking is used.
+
Task export feature now includes recurrence information, removes nested
+ quotes, and limits output to pending tasks.
From 2d2bd4707556a34fd36a210d5fec631a6f844074 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sat, 14 Mar 2009 13:47:48 -0400
Subject: [PATCH 090/103] Bug Fix - summary report included deleted tasks
- Applied patch from Benjamin Tegarden to exclude deleted tasks from
the summary report.
---
AUTHORS | 2 +-
ChangeLog | 2 ++
html/task.html | 2 ++
src/report.cpp | 9 +++++++--
4 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/AUTHORS b/AUTHORS
index 825c87b96..bab7cef3e 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -7,6 +7,7 @@ Contributing Authors:
H. İbrahim Güngör
Stefan Dorn
Michael Greb
+ Benjamin Tegarden
With thanks to:
Eugene Kramer
@@ -24,5 +25,4 @@ With thanks to:
Russell Friesenhahn
Paolo Marsi
Eric Farris
- Benjamin Tegarden
diff --git a/ChangeLog b/ChangeLog
index 1a0f7a89b..bf4907020 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -38,6 +38,8 @@
file locking is used.
+ Task export feature now includes recurrence information, removes nested
quotes, and limits output to pending tasks.
+ + Task no longer includes deleted tasks in the summary report (thanks to
+ Benjamin Tegarden).
------ old releases ------------------------------
diff --git a/html/task.html b/html/task.html
index fa0f4ded2..ed65b903a 100644
--- a/html/task.html
+++ b/html/task.html
@@ -132,6 +132,8 @@
file locking is used.
Task export feature now includes recurrence information, removes nested
quotes, and limits output to pending tasks.
+
Task no longer includes deleted tasks in the summary report (thanks to
+ Benjamin Tegarden).
diff --git a/src/report.cpp b/src/report.cpp
index 5820bd7c5..606a4e3ab 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -496,13 +496,18 @@ std::string handleReportSummary (TDB& tdb, T& task, Config& conf)
{
T task (completed[i]);
std::string project = task.getAttribute ("project");
- countCompleted[project] = countCompleted[project] + 1;
- ++counter[project];
+ if (task.getStatus () == T::deleted)
+ continue;
+
+ ++countCompleted[project];
time_t entry = ::atoi (task.getAttribute ("entry").c_str ());
time_t end = ::atoi (task.getAttribute ("end").c_str ());
if (entry && end)
+ {
sumEntry[project] = sumEntry[project] + (double) (end - entry);
+ ++counter[project];
+ }
}
// Create a table for output.
From df82fade2ca1e1badf835150f5c272d1a199b5df Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sun, 15 Mar 2009 11:31:27 -0400
Subject: [PATCH 091/103] Unit Tests - bug.summry, custom.columns, next
- Added unit tests to verify that the next report returns the correct
tasks.
- Added unit test to verify that unrecognized columns in a custom
report are flagged.
- Added unit tests to verify that only pending and completed tasks
are included in the summary report.
---
src/tests/bug.summary.t | 67 ++++++++++++++++++++++++++++++++++++++
src/tests/custom.columns.t | 57 ++++++++++++++++++++++++++++++++
src/tests/next.t | 61 ++++++++++++++++++++++++++++++++++
3 files changed, 185 insertions(+)
create mode 100755 src/tests/bug.summary.t
create mode 100755 src/tests/custom.columns.t
create mode 100755 src/tests/next.t
diff --git a/src/tests/bug.summary.t b/src/tests/bug.summary.t
new file mode 100755
index 000000000..c98b58d03
--- /dev/null
+++ b/src/tests/bug.summary.t
@@ -0,0 +1,67 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 6;
+
+# Create the rc file.
+if (open my $fh, '>', 'summary.rc')
+{
+ print $fh "data.location=.\n",
+ "confirmation=no\n";
+ close $fh;
+ ok (-r 'summary.rc', 'Created summary.rc');
+}
+
+# Add three tasks. Do 1, delete 1, leave 1 pending. Summary should depict a
+# 50% completion.
+qx{../task rc:summary.rc add project:A one};
+qx{../task rc:summary.rc add project:A two};
+qx{../task rc:summary.rc add project:A three};
+qx{../task rc:summary.rc do 1};
+qx{../task rc:summary.rc delete 2};
+my $output = qx{../task rc:summary.rc summary};
+like ($output, qr/A\s+1\s+-\s+50%/, 'summary correctly shows 50% before report');
+
+qx{../task rc:summary.rc list};
+$output = qx{../task rc:summary.rc summary};
+like ($output, qr/A\s+1\s+-\s+50%/, 'summary correctly shows 50% after report');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'completed.data';
+ok (!-r 'completed.data', 'Removed completed.data');
+
+unlink 'summary.rc';
+ok (!-r 'summary.rc', 'Removed summary.rc');
+
+exit 0;
+
diff --git a/src/tests/custom.columns.t b/src/tests/custom.columns.t
new file mode 100755
index 000000000..ab1927b65
--- /dev/null
+++ b/src/tests/custom.columns.t
@@ -0,0 +1,57 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 4;
+
+# Create the rc file.
+if (open my $fh, '>', 'custom.rc')
+{
+ print $fh "data.location=.\n",
+ "report.foo.description=DESC\n",
+ "report.foo.columns=id,foo,description\n",
+ "report.foo.sort=id+\n",
+ "report.foo.filter=project:A\n";
+ close $fh;
+ ok (-r 'custom.rc', 'Created custom.rc');
+}
+
+# Generate the usage screen, and locate the custom report on it.
+my $output = qx{../task rc:custom.rc foo 2>&1};
+like ($output, qr/Unrecognized column name: foo\n/, 'custom report spotted invalid column');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'custom.rc';
+ok (!-r 'custom.rc', 'Removed custom.rc');
+
+exit 0;
+
diff --git a/src/tests/next.t b/src/tests/next.t
new file mode 100755
index 000000000..2130f6626
--- /dev/null
+++ b/src/tests/next.t
@@ -0,0 +1,61 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 5;
+
+# Create the rc file.
+if (open my $fh, '>', 'next.rc')
+{
+ print $fh "data.location=.\n",
+ "next=1\n";
+ close $fh;
+ ok (-r 'next.rc', 'Created next.rc');
+}
+
+# Add two tasks for each of two projects, then run next. There should be only
+# one task from each project shown.
+qx{../task rc:next.rc add project:A priority:H AH};
+qx{../task rc:next.rc add project:A priority:M AM};
+qx{../task rc:next.rc add project:B priority:H BH};
+qx{../task rc:next.rc add project:B Bnone};
+
+my $output = qx{../task rc:next.rc next};
+like ($output, qr/\s1\sA\s+H\s+-\sAH\n/, 'AH shown');
+like ($output, qr/\s3\sB\s+H\s+-\sBH\n/, 'BH shown');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'next.rc';
+ok (!-r 'next.rc', 'Removed next.rc');
+
+exit 0;
+
From e33a918c2435cfbfb9afb55f3ec697cb177e227b Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sun, 15 Mar 2009 11:37:05 -0400
Subject: [PATCH 092/103] Bug Fix - summary report
- Fixed bug in summary report where recently completed (and therefore
not yet in the completed.data file) tasks were not included in the
report.
---
ChangeLog | 2 ++
html/task.html | 2 ++
src/report.cpp | 78 +++++++++++++++++++-------------------------------
3 files changed, 34 insertions(+), 48 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index bf4907020..e9c743989 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -40,6 +40,8 @@
quotes, and limits output to pending tasks.
+ Task no longer includes deleted tasks in the summary report (thanks to
Benjamin Tegarden).
+ + Fixed bug that prevented the summary report from properly reporting
+ recently completed tasks.
------ old releases ------------------------------
diff --git a/html/task.html b/html/task.html
index ed65b903a..e2336047c 100644
--- a/html/task.html
+++ b/html/task.html
@@ -134,6 +134,8 @@
quotes, and limits output to pending tasks.
Task no longer includes deleted tasks in the summary report (thanks to
Benjamin Tegarden).
+
Fixed bug that prevented the summary report from properly reporting
+ recently completed tasks.
diff --git a/src/report.cpp b/src/report.cpp
index 606a4e3ab..7b540b2d5 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -432,33 +432,23 @@ std::string handleInfo (TDB& tdb, T& task, Config& conf)
}
////////////////////////////////////////////////////////////////////////////////
-// Project Tasks Avg Age Status
-// A 12 13d XXXXXXXX------
-// B 109 3d 12h XX------------
+// Project Remaining Avg Age Complete 0% 100%
+// A 12 13d 55% XXXXXXXXXXXXX-----------
+// B 109 3d 12h 10% XXX---------------------
std::string handleReportSummary (TDB& tdb, T& task, Config& conf)
{
std::stringstream out;
- // Generate unique list of project names.
- std::map allProjects;
- std::vector pending;
- tdb.allPendingT (pending);
- handleRecurrence (tdb, pending);
- filter (pending, task);
- for (unsigned int i = 0; i < pending.size (); ++i)
- {
- T task (pending[i]);
- allProjects[task.getAttribute ("project")] = false;
- }
+ std::vector tasks;
+ tdb.allT (tasks);
+ handleRecurrence (tdb, tasks);
+ filter (tasks, task);
- std::vector completed;
- tdb.allCompletedT (completed);
- filter (completed, task);
- for (unsigned int i = 0; i < completed.size (); ++i)
- {
- T task (completed[i]);
- allProjects[task.getAttribute ("project")] = false;
- }
+ // Generate unique list of project names from all pending tasks.
+ std::map allProjects;
+ foreach (t, tasks)
+ if (t->getStatus () == T::pending)
+ allProjects[t->getAttribute ("project")] = false;
// Initialize counts, sum.
std::map countPending;
@@ -467,6 +457,7 @@ std::string handleReportSummary (TDB& tdb, T& task, Config& conf)
std::map counter;
time_t now = time (NULL);
+ // Initialize counters.
foreach (i, allProjects)
{
countPending [i->first] = 0;
@@ -475,38 +466,29 @@ std::string handleReportSummary (TDB& tdb, T& task, Config& conf)
counter [i->first] = 0;
}
- // Count the pending tasks.
- for (unsigned int i = 0; i < pending.size (); ++i)
+ // Count the various tasks.
+ foreach (t, tasks)
{
- T task (pending[i]);
- std::string project = task.getAttribute ("project");
- if (task.getStatus () == T::pending)
+ std::string project = t->getAttribute ("project");
+ ++counter[project];
+
+ if (t->getStatus () == T::pending)
+ {
++countPending[project];
- time_t entry = ::atoi (task.getAttribute ("entry").c_str ());
- if (entry)
- {
- sumEntry[project] = sumEntry[project] + (double) (now - entry);
- ++counter[project];
+ time_t entry = ::atoi (t->getAttribute ("entry").c_str ());
+ if (entry)
+ sumEntry[project] = sumEntry[project] + (double) (now - entry);
}
- }
- // Count the completed tasks.
- for (unsigned int i = 0; i < completed.size (); ++i)
- {
- T task (completed[i]);
- std::string project = task.getAttribute ("project");
- if (task.getStatus () == T::deleted)
- continue;
-
- ++countCompleted[project];
-
- time_t entry = ::atoi (task.getAttribute ("entry").c_str ());
- time_t end = ::atoi (task.getAttribute ("end").c_str ());
- if (entry && end)
+ else if (t->getStatus () == T::completed)
{
- sumEntry[project] = sumEntry[project] + (double) (end - entry);
- ++counter[project];
+ ++countCompleted[project];
+
+ time_t entry = ::atoi (t->getAttribute ("entry").c_str ());
+ time_t end = ::atoi (task.getAttribute ("end").c_str ());
+ if (entry && end)
+ sumEntry[project] = sumEntry[project] + (double) (end - entry);
}
}
From cd85a28e989b8f8dd62202cfeb940d097390edc4 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sun, 15 Mar 2009 15:04:52 -0400
Subject: [PATCH 093/103] Unit Tests - due, overdue
- Unit tests to verify that the "overdue" report is properly
displaying tasks.
- Unit tests to verify that "due" can be defined.
---
src/tests/due.t | 66 +++++++++++++++++++++++++++++++++++++++++++++
src/tests/overdue.t | 60 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 126 insertions(+)
create mode 100755 src/tests/due.t
create mode 100755 src/tests/overdue.t
diff --git a/src/tests/due.t b/src/tests/due.t
new file mode 100755
index 000000000..a032aa339
--- /dev/null
+++ b/src/tests/due.t
@@ -0,0 +1,66 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 14;
+
+# Create the rc file.
+if (open my $fh, '>', 'due.rc')
+{
+ print $fh "data.location=.\n",
+ "due=4\n",
+ "color=on\n",
+ "color.due=red\n",
+ "_forcecolor=on\n";
+ close $fh;
+ ok (-r 'due.rc', 'Created due.rc');
+}
+
+# Add a task that is almost due, and one that is just due.
+my ($d, $m, $y) = (localtime (time + 3 * 86_400))[3..5];
+my $just = sprintf ("%d/%02d/%d", $m + 1, $d, $y + 1900);
+
+($d, $m, $y) = (localtime (time + 5 * 86_400))[3..5];
+my $almost = sprintf ("%d/%02d/%d", $m + 1, $d, $y + 1900);
+
+qx{../task rc:due.rc add one due:$just};
+qx{../task rc:due.rc add two due:$almost};
+my $output = qx{../task rc:due.rc list};
+like ($output, qr/\[31m.+$just.+\[0m/, 'one marked due');
+like ($output, qr/\s+$almost\s+/, 'two not marked due');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'due.rc';
+ok (!-r 'due.rc', 'Removed due.rc');
+
+exit 0;
+
diff --git a/src/tests/overdue.t b/src/tests/overdue.t
new file mode 100755
index 000000000..94229c438
--- /dev/null
+++ b/src/tests/overdue.t
@@ -0,0 +1,60 @@
+#! /usr/bin/perl
+################################################################################
+## task - a command line task list manager.
+##
+## Copyright 2006 - 2009, Paul Beckingham.
+## All rights reserved.
+##
+## This program is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free Software
+## Foundation; either version 2 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, write to the
+##
+## Free Software Foundation, Inc.,
+## 51 Franklin Street, Fifth Floor,
+## Boston, MA
+## 02110-1301
+## USA
+##
+################################################################################
+
+use strict;
+use warnings;
+use Test::More tests => 6;
+
+# Create the rc file.
+if (open my $fh, '>', 'due.rc')
+{
+ print $fh "data.location=.\n",
+ "due=4\n";
+ close $fh;
+ ok (-r 'due.rc', 'Created due.rc');
+}
+
+# Add an overdue task, a due task, and a regular task. The "overdue" report
+# should list only the one task.
+qx{../task rc:due.rc add due:yesterday one};
+qx{../task rc:due.rc add due:tomorrow two};
+qx{../task rc:due.rc add due:eoy three};
+my $output = qx{../task rc:due.rc overdue};
+like ($output, qr/one/, 'overdue: task 1 shows up');
+unlike ($output, qr/two/, 'overdue: task 2 does not show up');
+unlike ($output, qr/three/, 'overdue: task 3 does not show up');
+
+# Cleanup.
+unlink 'pending.data';
+ok (!-r 'pending.data', 'Removed pending.data');
+
+unlink 'due.rc';
+ok (!-r 'due.rc', 'Removed due.rc');
+
+exit 0;
+
From a3882160fa73b52fa7535177700c1822755a916e Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sun, 15 Mar 2009 15:12:16 -0400
Subject: [PATCH 094/103] Documentation Update
- Updated docs to reflect the 1.5.0 release date.
---
ChangeLog | 2 +-
html/task.html | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index e9c743989..794dc591a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,7 @@
------ current release ---------------------------
-1.5.0 (?)
+1.5.0 (3/15/2009)
+ Removed deprecated TUTORIAL file.
+ Removed "showage" configuration variable.
+ "task stop" can now remove the start time from a started task.
diff --git a/html/task.html b/html/task.html
index e2336047c..1534e1542 100644
--- a/html/task.html
+++ b/html/task.html
@@ -94,7 +94,7 @@
-->
-
New in version 1.5.0 (?)
+
New in version 1.5.0 (3/15/2009)
Removed deprecated TUTORIAL file.
Removed support for the "showage" configuration variable.
From 4baf30cf9c320415da13b379f933cf8b833e50a0 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sun, 15 Mar 2009 16:13:02 -0400
Subject: [PATCH 095/103] Portability - Ubuntu 8
- Changed unsigned int to size_t for std::string::npos comparison.
- Removed validBuiltinCommand function that is not used.
---
src/parse.cpp | 14 +-------------
1 file changed, 1 insertion(+), 13 deletions(-)
diff --git a/src/parse.cpp b/src/parse.cpp
index b0a1c5197..b5adb8388 100644
--- a/src/parse.cpp
+++ b/src/parse.cpp
@@ -342,18 +342,6 @@ static bool validCommand (std::string& input)
return true;
}
-////////////////////////////////////////////////////////////////////////////////
-static bool validBuiltinCommand (std::string& input)
-{
- std::string copy = input;
- guess ("command", commands, copy);
- if (copy == "")
- return false;
-
- input = copy;
- return true;
-}
-
////////////////////////////////////////////////////////////////////////////////
static bool validSubstitution (
std::string& input,
@@ -509,7 +497,7 @@ void loadCustomReports (Config& conf)
if (i->substr (0, 7) == "report.")
{
std::string report = i->substr (7, std::string::npos);
- unsigned int columns = report.find (".columns");
+ size_t columns = report.find (".columns");
if (columns != std::string::npos)
{
report = report.substr (0, columns);
From 429d0f307150409d1d541972262579724f62c1d5 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sun, 15 Mar 2009 16:14:16 -0400
Subject: [PATCH 096/103] Portability - Fedora 9
- Compiler pointed out an expression (a || b && c) that clearly needs
parentheses around (a || b). Gcc on other OSes don't mention this.
---
src/report.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/report.cpp b/src/report.cpp
index 7b540b2d5..44752327a 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -934,7 +934,7 @@ std::string handleReportHistory (TDB& tdb, T& task, Config& conf)
}
table.addCell (row, 5, net);
- if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false) && net)
+ if ((conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false)) && net)
table.setCellFg (row, 5, net > 0 ? Text::red: Text::green);
}
From 65f74da7a48294b43aadc5495b8f5070e964aa5f Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sun, 15 Mar 2009 16:26:20 -0400
Subject: [PATCH 097/103] Portability - Fedora 9
- Using size_t as a result for std::string::find causes a silent error,
reported only on Ubuntu 8. size_t is not large enough. The proper
result type is std::string::size_type. This fixes a problem with
the command "task old" responding with "Ambiguous commane 'old' -
could be one of oldest, oldest.description, oldest.limit, oldest.sort".
---
src/parse.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/parse.cpp b/src/parse.cpp
index b5adb8388..a8e41a914 100644
--- a/src/parse.cpp
+++ b/src/parse.cpp
@@ -497,7 +497,7 @@ void loadCustomReports (Config& conf)
if (i->substr (0, 7) == "report.")
{
std::string report = i->substr (7, std::string::npos);
- size_t columns = report.find (".columns");
+ std::string::size_type columns = report.find (".columns");
if (columns != std::string::npos)
{
report = report.substr (0, columns);
From b5690f00e2e27a3336eb06e77f4331e5e05a05d6 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sun, 15 Mar 2009 16:39:41 -0400
Subject: [PATCH 098/103] Portabiliy - Fedora 9, Ubuntu 8
- The custom report limit "report.x.limit" was being used to limit the
rendered rows in the table. Instead, there should be something like
min (limit, actual_rows) used, in Table.cpp.
The symptom was duplicate tasks in a "task oldest" report, when there
were less than 10 tasks.
---
src/Table.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Table.cpp b/src/Table.cpp
index 8052ca0b3..6f20c1b50 100644
--- a/src/Table.cpp
+++ b/src/Table.cpp
@@ -1032,7 +1032,7 @@ const std::string Table::render (int maximum /* = 0 */)
// the table that are rendered.
int limit = mRows;
if (maximum != 0)
- limit = maximum;
+ limit = min (maximum, mRows);
// Print all rows.
for (int row = 0; row < limit; ++row)
From e8a795befbbe7570f7483cd1027fecebdcbe0a44 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sun, 15 Mar 2009 17:01:22 -0400
Subject: [PATCH 099/103] Unit Tests - due, export
- due.t was incorrectly reporting the number of tests it intended to
run.
- export.t was not updated when the export command was updated to include
recurrence information.
---
src/tests/due.t | 2 +-
src/tests/export.t | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/tests/due.t b/src/tests/due.t
index a032aa339..b320c9563 100755
--- a/src/tests/due.t
+++ b/src/tests/due.t
@@ -28,7 +28,7 @@
use strict;
use warnings;
-use Test::More tests => 14;
+use Test::More tests => 5;
# Create the rc file.
if (open my $fh, '>', 'due.rc')
diff --git a/src/tests/export.t b/src/tests/export.t
index 4218a3c10..143a687da 100755
--- a/src/tests/export.t
+++ b/src/tests/export.t
@@ -50,9 +50,9 @@ if (open my $fh, '<', './export.txt')
close $fh;
}
-my $line1 = qr/'id','uuid','status','tags','entry','start','due','end','project','priority','fg','bg','description'\n/;
-my $line2 = qr/'.{8}-.{4}-.{4}-.{4}-.{12}','pending','',\d+,,,,'A','H',,,'one'\n/;
-my $line3 = qr/'.{8}-.{4}-.{4}-.{4}-.{12}','pending','tag1 tag2',\d+,,,,,,,,'two'\n/;
+my $line1 = qr/'id','uuid','status','tags','entry','start','due','recur','end','project','priority','fg','bg','description'\n/;
+my $line2 = qr/'.{8}-.{4}-.{4}-.{4}-.{12}','pending','',\d+,,,,,'A','H',,,'one'\n/;
+my $line3 = qr/'.{8}-.{4}-.{4}-.{4}-.{12}','pending','tag1 tag2',\d+,,,,,,,,,'two'\n/;
like ($lines[0], $line1, "export line one");
like ($lines[1], $line2, "export line two");
From 8efd8620c84df83ad44f7adada1c94c7a9498384 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sun, 15 Mar 2009 17:21:54 -0400
Subject: [PATCH 100/103] Portability - Ubuntu 8.10
- When creating a new .taskrc file, no newlines were included at EOL.
This needs a 1.5.1 regression test.
---
src/Config.cpp | 34 +++++++++++++++++-----------------
1 file changed, 17 insertions(+), 17 deletions(-)
diff --git a/src/Config.cpp b/src/Config.cpp
index 3476bc6f8..c2cb928fc 100644
--- a/src/Config.cpp
+++ b/src/Config.cpp
@@ -175,27 +175,27 @@ void Config::createDefault (const std::string& home)
fprintf (out, "# Filter: pro:x pri:H +bug\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.long.description=Lists all task, all data, matching the specified criteria\n");
+ fprintf (out, "report.long.columns=id,project,priority,entry,start,due,recur,age,tags,description\n");
+ fprintf (out, "report.long.sort=due+,priority-,project+\n");
- 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.list.description=Lists all tasks matching the specified criteria\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.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.ls.description=Minimal listing of all tasks matching the specified criteria\n");
+ fprintf (out, "report.ls.columns=id,project,priority,description\n");
+ fprintf (out, "report.ls.sort=priority-,project+\n");
- 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.newest.description=Shows the newest tasks\n");
+ fprintf (out, "report.newest.columns=id,project,priority,due,active,age,description\n");
+ fprintf (out, "report.newest.sort=id-\n");
+ fprintf (out, "report.newest.limit=10\n");
- 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");
+ fprintf (out, "report.oldest.description=Shows the oldest tasks\n");
+ fprintf (out, "report.oldest.columns=id,project,priority,due,active,age,description\n");
+ fprintf (out, "report.oldest.sort=id+\n");
+ fprintf (out, "report.oldest.limit=10\n");
fclose (out);
From f8af5d999af800850cd0d7792fc03158cb1ee288 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sun, 15 Mar 2009 17:38:54 -0400
Subject: [PATCH 101/103] Unit Tests - run_all
- Added script to run all unit tests and capture output.
---
src/tests/run_all | 11 +++++++++++
1 file changed, 11 insertions(+)
create mode 100755 src/tests/run_all
diff --git a/src/tests/run_all b/src/tests/run_all
new file mode 100755
index 000000000..f92ea5412
--- /dev/null
+++ b/src/tests/run_all
@@ -0,0 +1,11 @@
+!# /bin/bash
+
+date > all.log
+
+for i in *.t
+do
+ ./$i >> all.log 2>&1
+done
+
+date >> all.log
+
From 7b1dec0d776f9540f9e869986f0166834752d2a9 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sun, 15 Mar 2009 19:15:35 -0400
Subject: [PATCH 102/103] Bug Fix - abbreviation.t
- abbreviation.t contains unit tests that fail to specify an alternate
rc file (rc:abbrev.rc), and so instead rely on ~/.taskrc. For a new
installation, there is no .taskrc, so task offers to create one.
When done in the context of a unit test, task hangs waiting for input.
---
src/tests/abbreviation.t | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/src/tests/abbreviation.t b/src/tests/abbreviation.t
index 18d330e65..4f798c0ee 100755
--- a/src/tests/abbreviation.t
+++ b/src/tests/abbreviation.t
@@ -67,25 +67,25 @@ like ($output, qr/\bwith\b/, 'pri:H with');
unlike ($output, qr/\bwithout\b/, 'pri:H without');
# Test the version command abbreviations.
-$output = qx{../task version};
+$output = qx{../task rc:abbrev.rc version};
like ($output, qr/ABSOLUTELY NO WARRANTY/, 'version');
-$output = qx{../task versio};
+$output = qx{../task rc:abbrev.rc versio};
like ($output, qr/ABSOLUTELY NO WARRANTY/, 'versio');
-$output = qx{../task versi};
+$output = qx{../task rc:abbrev.rc versi};
like ($output, qr/ABSOLUTELY NO WARRANTY/, 'versi');
-$output = qx{../task vers};
+$output = qx{../task rc:abbrev.rc vers};
like ($output, qr/ABSOLUTELY NO WARRANTY/, 'vers');
-$output = qx{../task ver};
+$output = qx{../task rc:abbrev.rc ver};
like ($output, qr/ABSOLUTELY NO WARRANTY/, 'ver');
-$output = qx{../task ve};
+$output = qx{../task rc:abbrev.rc ve};
like ($output, qr/ABSOLUTELY NO WARRANTY/, 've');
-$output = qx{../task v};
+$output = qx{../task rc:abbrev.rc v};
like ($output, qr/ABSOLUTELY NO WARRANTY/, 'v');
# Cleanup.
From 87be68e2e83d7bb628be1e5679b16a49a26d3549 Mon Sep 17 00:00:00 2001
From: Paul Beckingham
Date: Sun, 15 Mar 2009 22:12:18 -0400
Subject: [PATCH 103/103] Bug Fix
- Shebang in tests/run_all was backwards.
---
src/tests/run_all | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/tests/run_all b/src/tests/run_all
index f92ea5412..9853f957f 100755
--- a/src/tests/run_all
+++ b/src/tests/run_all
@@ -1,4 +1,4 @@
-!# /bin/bash
+#! /bin/bash
date > all.log