Merge branch 'master' into 1.5.0

Conflicts:
	ChangeLog
	NEWS
	configure.ac
	html/task.html
	src/task.cpp
	src/task.h
This commit is contained in:
Paul Beckingham 2008-11-02 22:29:38 -05:00
commit ee961daef6
29 changed files with 813 additions and 447 deletions

View file

@ -11,14 +11,18 @@
------ old releases ------------------------------ ------ old releases ------------------------------
1.4.3 (10/9/2008) 1.4.3 (11/1/2008)
+ Fixed misleading task count at bottom on "info" report. + Fixed misleading task count at bottom on "info" report.
+ Added support for a shadow file that contains a plain text task report, + Added support for a shadow file that contains a plain text task report,
with the "shadow.file" and "shadow.command" configuration variables. with the "shadow.file" and "shadow.command" configuration variables
The shadow file is automatically updated whenever the task database The shadow file is automatically updated whenever the task database
changes. Useful for integrating with "Samurize". changes. Useful for integrating with "Samurize"
+ Task now displays a message whenever a shadow file is updated, if the
------ old releases ------------------------------ "shadow.notify" configuration variable is set "on"
+ Bug: adding a task with a \n, \r or \f in it now fails properly
+ Removed "task usage" command.
+ Added documentation for Shadow files.
+ Added documentation for task filters.
1.4.2 (9/18/2008) 1.4.2 (9/18/2008)
+ "task undo" can now retract a "task done" command, provided no reports + "task undo" can now retract a "task done" command, provided no reports

View file

@ -1,36 +0,0 @@
Some considerable time ago - longer than I had hoped - I demonstrated an
alternate implementation of the todo script, called task, in the form of a
YouTube movie:
http://www.youtube.com/watch?v=l68LCl6BYvs
A lot has happened since then, and the task program has been slowly improving
thanks to feedback from some early testers, and continuous use by me. Today,
I have uploaded a new movie:
http://www.youtube.com/watch?v=D2Kn4DMOVSw
This movie includes most of the changes and improvements to task, but behind
the scenes are the biggest changes. There was a rewrite of the underlying
storage mechanism yielding a clean API for the front end, and the code was
reviewed for portability and converted to use GNU autoconf/automake.
Task has been released under GPL, and so far has been tested on:
Max OS X 10.4 (Tiger)
Max OS X 10.5 (Leopard)
Fedora 8
Fedora 9
Ubuntu 8 (Hardy Heron)
Solaris 10
Task has been making me more organized and productive for some time now.
Perhaps some of you might find it useful, and I welcome feedback of all kinds.
You can find the task source code at:
http://www.beckingham.net/task-1.0.0.tar.gz
Thank you.
Paul Beckingham

View file

@ -19,7 +19,7 @@ AC_CHECK_LIB(ncurses,endwin)
# Checks for header files. # Checks for header files.
AC_HEADER_STDC AC_HEADER_STDC
AC_CHECK_HEADERS([stdlib.h sys/file.h sys/stat.h sys/time.h unistd.h]) AC_CHECK_HEADERS([stdlib.h sys/file.h sys/stat.h sys/time.h unistd.h])
AC_CHECK_HEADERS([string vector map]) AC_CHECK_HEADERS([sstream string vector map])
# Checks for typedefs, structures, and compiler characteristics. # Checks for typedefs, structures, and compiler characteristics.
AC_HEADER_STDBOOL AC_HEADER_STDBOOL

View file

@ -25,6 +25,7 @@
<a href="date.html">Date Handling</a> <a href="date.html">Date Handling</a>
<a href="troubleshooting.html">Troubleshooting</a> <a href="troubleshooting.html">Troubleshooting</a>
<a href="versions.html">Old Versions</a> <a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div> </div>
<div id="content"> <div id="content">

View file

@ -25,6 +25,7 @@
<a href="date.html">Date Handling</a> <a href="date.html">Date Handling</a>
<a href="troubleshooting.html">Troubleshooting</a> <a href="troubleshooting.html">Troubleshooting</a>
<a href="versions.html">Old Versions</a> <a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div> </div>
<div id="content"> <div id="content">

View file

@ -25,6 +25,7 @@
<a href="date.html">Date Handling</a> <a href="date.html">Date Handling</a>
<a href="troubleshooting.html">Troubleshooting</a> <a href="troubleshooting.html">Troubleshooting</a>
<a href="versions.html">Old Versions</a> <a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div> </div>
<div id="content"> <div id="content">

View file

@ -25,6 +25,7 @@
<a href="date.html">Date Handling</a> <a href="date.html">Date Handling</a>
<a href="troubleshooting.html">Troubleshooting</a> <a href="troubleshooting.html">Troubleshooting</a>
<a href="versions.html">Old Versions</a> <a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div> </div>
<div id="content"> <div id="content">
@ -315,6 +316,12 @@ ID Project Pri Description
</p> </p>
</dd> </dd>
<dt>shadow.notify</dt>
<dd>
When this value is set to "on", task will display a message
whenever the shadow file is updated by some task command.
</dd>
</div> </div>
<br /> <br />

View file

@ -25,6 +25,7 @@
<a href="date.html">Date Handling</a> <a href="date.html">Date Handling</a>
<a href="troubleshooting.html">Troubleshooting</a> <a href="troubleshooting.html">Troubleshooting</a>
<a href="versions.html">Old Versions</a> <a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div> </div>
<div id="content"> <div id="content">

View file

@ -25,6 +25,7 @@
<a href="date.html">Date Handling</a> <a href="date.html">Date Handling</a>
<a href="troubleshooting.html">Troubleshooting</a> <a href="troubleshooting.html">Troubleshooting</a>
<a href="versions.html">Old Versions</a> <a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div> </div>
<div id="content"> <div id="content">
@ -34,10 +35,49 @@
<h2 class="title">Task Filters</h2> <h2 class="title">Task Filters</h2>
<div class="content"> <div class="content">
<p> <p>
A task filter is a means of reducing a task report to a
subset that may consist of all tasks that have a specific
project, priority, tag, or part of the description.
</p>
<p>
A task filter consists of additional command line options,
that are specified in the same way as when a task is added.
</p>
<p>
All task reports can make use of filters.
</p>
<p>
For example, the report:
</p>
<code><pre>% task list</pre></code>
<p>
Lists all tasks.
</p>
<code><pre>% task list the</pre></code>
<p>
Lists only tasks with "the" in the task description.
</p>
<code><pre>% task list project:Home priority:H</pre></code>
<p>
Lists only tasks with both the "Home" project and "H" priority.
</p>
<code><pre>% task list +shopping</pre></code>
<p>
Lists only tasks with the "shopping" tag.
</p> </p>
</div> </div>
<br /> <br />
<br /> <br />
<div class="content"> <div class="content">

188
html/links.html Normal file
View file

@ -0,0 +1,188 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Task on the Web</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="task.css" type="text/css" />
</head>
<body>
<div id="container">
<table>
<tr>
<td>
<div id="toolbar">
<a href="task.html">Home</a>
<a href="setup.html">Setup</a>
<a href="30second.html">30-second Tutorial</a>
<a href="simple.html">Simple</a>
<a href="advanced.html">Advanced</a>
<a href="shell.html">Shell</a>
<a href="config.html">Configuration</a>
<a href="color.html">Colors</a>
<a href="usage.html">Usage</a>
<a href="recur.html">Recurrence</a>
<a href="date.html">Date Handling</a>
<a href="troubleshooting.html">Troubleshooting</a>
<a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div>
<div id="content">
<br />
<br />
<br />
<h1 class="title">Task on the Web</h1>
<p>
Task links from around the web...
</p>
<dt>
November 2008, <a href="http://github.com/pbeckingham/task/tree/master/">Task repository on GitHub</a>
</dt>
<dd>
For developers: the task git repository on github.com is now public.
</dd>
<br>
<dt>
October 2008, <a href="http://blog.rfquerin.org/2008/10/07/using-task-and-dropbox-to-manage-your-to-do-list/">Using Task and Dropbox to manage your To-Do list</a>
</dt>
<dd>
by Richard Querin. Richard discusses the ease of setting up task to
use DropBox to share todo lists between work and home.
</dd>
<br>
<dt>
September 2008, <a href="http://stasantons.blogspot.com/2008/09/task-program-visually-simple.html">Task visualization</a>
</dt>
<dd>
by Stas Antons. Stas - a colleague of mine - presents a visualization
of the simplicity of task.
</dd>
<br>
<dt>
June 2008, <a href="http://blog.rfquerin.org/2008/06/17/building-debian-packages-for-task/">Building Debian Packages For Task</a>
</dt>
<dd>
by Richard Querin. Richard has been providing Debian packages for the
various task releases, and discusses how he got up to speed.
</dd>
<br>
<dt>
June 2008, <a href="http://blog.rfquerin.org/2008/06/06/task-101-an-attempt-at-a-cygwin-build-how-to/">Task 1.0.1 - an attempt at a Cygwin Build How-To</a>
</dt>
<dd>
by Richard Querin. Richard shows us how to build task using Cygwin, after
a cry for help on the todo.txt mailing list.
</dd>
<br>
<dt>
June 2008, <a href="http://www.youtube.com/watch?v=D2Kn4DMOVSw">The second task movie</a>
</dt>
<dd>
This YouTube movie was made to illustrate some of the features of the task
program, back when task 1.0.0 was released. While task has grown
significantly since then, the commands shown are still valid. It will
soon be time for a new movie!
<p>
This movie has a voice-over that explains what is going on.
<p>
For a higher-quality version, download the whole
<a href="http://www.beckingham.net/todo2.mov">movie file (10MB)</a>.
</dd>
<br>
<dt>
December 2006, <a href="http://www.youtube.com/watch?v=l68LCl6BYvs">The first task movie</a>
</dt>
<dd>
This original YouTube task movie was made to illustrate the features of the
then-unreleased task program. The idea was to get some feedback and see
whether anyone was interested in a new implementation of todo.sh, that added
features that are not easily possible with a shell implementation.
<p>
This movie has no voice-over, and you may notice that it exactly duplicates
the commands used in the original todo.sh movie (below). That is, until it
deviates because of new task commands.
</dd>
<br>
<dt>
June 2006, <a href="http://www.youtube.com/watch?v=daJ1Hs_y738">The original todo.sh movie</a>
</dt>
<dd>
by Gina Trapani. This is the original YouTube todo.sh movie, made to
illustrate the power and simplicity of the original todo.sh program.
</dd>
<br>
<dt>
June 2006, <a href="http://todotxt.com/">Todo.sh, the inspiration for task</a>
</dt>
<dd>
by Gina Trapani. The website that introduced me to the power and
simplicity of the original todo.sh program. Contains useful links
and resources - take a look!
</dd>
<br />
<br />
<div class="content">
<p>
Copyright 2006-2008, P. Beckingham. All rights reserved.
</p>
</div>
</div>
</td>
<td align="right" valign="top" width="200px">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9709799404235424";
/* Task Main */
google_ad_slot = "8660617875";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-4737637-1");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>

View file

@ -25,6 +25,7 @@
<a href="date.html">Date Handling</a> <a href="date.html">Date Handling</a>
<a href="troubleshooting.html">Troubleshooting</a> <a href="troubleshooting.html">Troubleshooting</a>
<a href="versions.html">Old Versions</a> <a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div> </div>
<div id="content"> <div id="content">

View file

@ -25,6 +25,7 @@
<a href="date.html">Date Handling</a> <a href="date.html">Date Handling</a>
<a href="troubleshooting.html">Troubleshooting</a> <a href="troubleshooting.html">Troubleshooting</a>
<a href="versions.html">Old Versions</a> <a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div> </div>
<div id="content"> <div id="content">

View file

@ -25,6 +25,7 @@
<a href="date.html">Date Handling</a> <a href="date.html">Date Handling</a>
<a href="troubleshooting.html">Troubleshooting</a> <a href="troubleshooting.html">Troubleshooting</a>
<a href="versions.html">Old Versions</a> <a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div> </div>
<div id="content"> <div id="content">
@ -34,10 +35,42 @@
<h2 class="title">Task Shadow Files</h2> <h2 class="title">Task Shadow Files</h2>
<div class="content"> <div class="content">
<p> <p>
A shadow file is a text file containing a copy of a task
report. It is automatically maintained by task whenever
something changes in the task database.
</p>
<p>
This means there is always a current version of the task
report kept in a text file. Products such as
<a href="www.samurize.com">Samurize</a>,
<a href="http://www.mulle-kybernetik.com/software/MkConsole/">MkConsole</a>,
or
<a href="http://projects.tynsoe.org/en/geektool/">GeekTool</a>
can display this file on the computer desktop, so that it
is readily visible.
</p>
<p>
To use a shadow file, edit your .taskrc configuration file,
and add two entries as shown:
</p>
<pre><code>shadow.file=/path/to/file
shadow.command=list pri:H</code></pre>
<p>
In this example the shadow file contains a report equivalent
to running "task list pri:H".
</p>
<p>
You can use any task command that generates a report, and of
course, you can specify any file name, provided the directory
it resides in already exists.
</p> </p>
</div> </div>
<br /> <br />
<br /> <br />
<div class="content"> <div class="content">

View file

@ -25,6 +25,7 @@
<a href="date.html">Date Handling</a> <a href="date.html">Date Handling</a>
<a href="troubleshooting.html">Troubleshooting</a> <a href="troubleshooting.html">Troubleshooting</a>
<a href="versions.html">Old Versions</a> <a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div> </div>
<div id="content"> <div id="content">

View file

@ -25,6 +25,7 @@
<a href="date.html">Date Handling</a> <a href="date.html">Date Handling</a>
<a href="troubleshooting.html">Troubleshooting</a> <a href="troubleshooting.html">Troubleshooting</a>
<a href="versions.html">Old Versions</a> <a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div> </div>
<div id="content"> <div id="content">

View file

@ -25,6 +25,7 @@
<a href="date.html">Date Handling</a> <a href="date.html">Date Handling</a>
<a href="troubleshooting.html">Troubleshooting</a> <a href="troubleshooting.html">Troubleshooting</a>
<a href="versions.html">Old Versions</a> <a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div> </div>
<div id="content"> <div id="content">
@ -54,8 +55,8 @@
<li><a href="date.html">Date Handling</a> <li><a href="date.html">Date Handling</a>
<li><a href="troubleshooting.html">Troubleshooting</a> <li><a href="troubleshooting.html">Troubleshooting</a>
<li><a href="versions.html">Old Versions</a> <li><a href="versions.html">Old Versions</a>
<li><a href="filter.html">Filters (coming soon)</a> <li><a href="filter.html">Filters</a>
<li><a href="shadow.html">Shadow Files (coming soon)</a> <li><a href="shadow.html">Shadow Files</a>
</ul> </ul>
<p> <p>
@ -77,6 +78,7 @@
<td>Source:</td> <td>Source:</td>
<td><a href="http://www.beckingham.net/task-1.5.0.tar.gz">task-1.5.0.tar.gz</a></td> <td><a href="http://www.beckingham.net/task-1.5.0.tar.gz">task-1.5.0.tar.gz</a></td>
</tr> </tr>
<!--
<tr> <tr>
<td>Mac OS X 10.5 (Leopard) Intel-only:</td> <td>Mac OS X 10.5 (Leopard) Intel-only:</td>
<td><a href="http://www.beckingham.net/task-1.5.0.pkg">task-1.5.0.pkg</a></td> <td><a href="http://www.beckingham.net/task-1.5.0.pkg">task-1.5.0.pkg</a></td>
@ -88,13 +90,12 @@
</td> </td>
<td><a href="http://www.beckingham.net/task_1.5.0-1_i386.deb">task_1.5.0-1_i386.deb</a></td> <td><a href="http://www.beckingham.net/task_1.5.0-1_i386.deb">task_1.5.0-1_i386.deb</a></td>
</tr> </tr>
-->
</table> </table>
<h4>New in version 1.5.0 (?)</h4> <h4>New in version 1.5.0 (?)</h4>
<ul> <ul>
<li>Removed deprecated TUTORIAL file. <li>Removed deprecated TUTORIAL file.
<li>Removed "usage" command, and support for "command.logging" configuration
variable.
<li>"task stop" can remove the start time from a started task. <li>"task stop" can remove the start time from a started task.
<li>"task ghistory" now displays a differently aligned graph, allowing <li>"task ghistory" now displays a differently aligned graph, allowing
easier comparison by month of tasks added versus completed and deleted. easier comparison by month of tasks added versus completed and deleted.

View file

@ -25,6 +25,7 @@
<a href="date.html">Date Handling</a> <a href="date.html">Date Handling</a>
<a href="troubleshooting.html">Troubleshooting</a> <a href="troubleshooting.html">Troubleshooting</a>
<a href="versions.html">Old Versions</a> <a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div> </div>
<div id="content"> <div id="content">

View file

@ -25,6 +25,7 @@
<a href="date.html">Date Handling</a> <a href="date.html">Date Handling</a>
<a href="troubleshooting.html">Troubleshooting</a> <a href="troubleshooting.html">Troubleshooting</a>
<a href="versions.html">Old Versions</a> <a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div> </div>
<div id="content"> <div id="content">

View file

@ -25,6 +25,7 @@
<a href="date.html">Date Handling</a> <a href="date.html">Date Handling</a>
<a href="troubleshooting.html">Troubleshooting</a> <a href="troubleshooting.html">Troubleshooting</a>
<a href="versions.html">Old Versions</a> <a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div> </div>
<div id="content"> <div id="content">
@ -35,6 +36,32 @@
<br /> <br />
<div class="content"> <div class="content">
<p>
<h4>New in version 1.4.3 (11/1/2008)</h4>
<a href="http://www.beckingham.net/task-1.4.3.tar.gz">task-1.4.3.tar.gz</a>
<br />
Mac OS X 10.5 (Leopard) Intel-only:
<a href="http://www.beckingham.net/task-1.4.3.pkg">task-1.4.3.pkg</a>
<br />
Debian package: <a href="http://www.beckingham.net/task_1.4.3-1_i386.deb">task_1.4.3-1_i386.deb</a>
(Thanks to <a href="http://blog.rfquerin.org">Richard Querin</a>)
</p>
<ul>
<li>Fixed misleading task count at bottom of "info" report.
<li>Added support for a shadow file that contains a plain text task report,
with the "shadow.file" and "shadow.command" configuration variables.
The shadow file is automatically updated whenever the task database
changes. Useful for integrating with "Samurize".
<li>Task now displays a message whenever a shadow file is updated, if the
"shadow.notify" configuration variable is set "on".
<li>Fixed bug whereby adding a task with a \n, \r or \f dit not fail properly.
<li>Removed "task usage" command.
<li>Added documentation for Shadow files.
<li>Added documentation for task filters.
</ul>
</p>
<p> <p>
<h4>New in version 1.4.2 (9/18/2008)</h4> <h4>New in version 1.4.2 (9/18/2008)</h4>
<a href="http://www.beckingham.net/task-1.4.2.tar.gz">task-1.4.2.tar.gz</a> <a href="http://www.beckingham.net/task-1.4.2.tar.gz">task-1.4.2.tar.gz</a>

1
src/.gitignore vendored
View file

@ -1,2 +1 @@
./Makefile
*.o *.o

View file

@ -130,6 +130,10 @@ void Config::createDefault (const std::string& home)
fprintf (out, "#color.tag.bug=yellow\n"); fprintf (out, "#color.tag.bug=yellow\n");
fprintf (out, "#color.project.home=on_green\n"); fprintf (out, "#color.project.home=on_green\n");
fprintf (out, "#color.keyword.car=on_blue\n"); fprintf (out, "#color.keyword.car=on_blue\n");
fprintf (out, "#shadow.file=%s/shadow.txt\n", dataDir.c_str ());
fprintf (out, "#shadow.command=list\n");
fprintf (out, "#shadow.notify=on\n");
fprintf (out, "#default.command=list\n");
fclose (out); fclose (out);

View file

@ -204,9 +204,7 @@ bool TDB::deleteT (const T& t)
sprintf (endTime, "%u", (unsigned int) time (NULL)); sprintf (endTime, "%u", (unsigned int) time (NULL));
it->setAttribute ("end", endTime); it->setAttribute ("end", endTime);
bool status = overwritePending (all); return overwritePending (all);
dbChanged ();
return status;
} }
return false; return false;
@ -230,9 +228,7 @@ bool TDB::completeT (const T& t)
sprintf (endTime, "%u", (unsigned int) time (NULL)); sprintf (endTime, "%u", (unsigned int) time (NULL));
it->setAttribute ("end", endTime); it->setAttribute ("end", endTime);
bool status = overwritePending (all); return overwritePending (all);
dbChanged ();
return status;
} }
return false; return false;
@ -259,14 +255,10 @@ bool TDB::addT (const T& t)
if (task.getStatus () == T::pending || if (task.getStatus () == T::pending ||
task.getStatus () == T::recurring) task.getStatus () == T::recurring)
{ {
bool status = writePending (task); return writePending (task);
dbChanged ();
return status;
} }
bool status = writeCompleted (task); return writeCompleted (task);
dbChanged ();
return status;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -291,9 +283,7 @@ bool TDB::modifyT (const T& t)
pending.push_back (*it); pending.push_back (*it);
} }
bool status = overwritePending (pending); return overwritePending (pending);
dbChanged ();
return status;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -324,6 +314,7 @@ bool TDB::overwritePending (std::vector <T>& all)
fputs (it->compose ().c_str (), out); fputs (it->compose ().c_str (), out);
fclose (out); fclose (out);
dbChanged ();
return true; return true;
} }
@ -331,7 +322,7 @@ bool TDB::overwritePending (std::vector <T>& all)
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool TDB::writePending (const T& t) const bool TDB::writePending (const T& t)
{ {
// Write a single task to the pending file // Write a single task to the pending file
FILE* out; FILE* out;
@ -346,6 +337,7 @@ bool TDB::writePending (const T& t) const
fputs (t.compose ().c_str (), out); fputs (t.compose ().c_str (), out);
fclose (out); fclose (out);
dbChanged ();
return true; return true;
} }
@ -353,7 +345,7 @@ bool TDB::writePending (const T& t) const
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool TDB::writeCompleted (const T& t) const bool TDB::writeCompleted (const T& t)
{ {
// Write a single task to the pending file // Write a single task to the pending file
FILE* out; FILE* out;
@ -368,6 +360,8 @@ bool TDB::writeCompleted (const T& t) const
fputs (t.compose ().c_str (), out); fputs (t.compose ().c_str (), out);
fclose (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; return true;
} }
@ -439,8 +433,11 @@ int TDB::gc ()
} }
} }
// Dump all clean tasks into pending. // Dump all clean tasks into pending. But don't bother unless at least one
// task was transferred.
if (count)
overwritePending (pending); overwritePending (pending);
return count; return count;
} }

View file

@ -56,8 +56,8 @@ public:
private: private:
bool lock (FILE*) const; bool lock (FILE*) const;
bool overwritePending (std::vector <T>&); bool overwritePending (std::vector <T>&);
bool writePending (const T&) const; bool writePending (const T&);
bool writeCompleted (const T&) const; bool writeCompleted (const T&);
bool readLockedFile (const std::string&, std::vector <std::string>&) const; bool readLockedFile (const std::string&, std::vector <std::string>&) const;
void dbChanged (); void dbChanged ();

View file

@ -26,6 +26,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <sstream>
#include <fstream> #include <fstream>
#include <sys/types.h> #include <sys/types.h>
#include <stdio.h> #include <stdio.h>
@ -67,7 +68,6 @@ void handleAdd (TDB& tdb, T& task, Config& conf)
task.setAttribute ("mask", ""); task.setAttribute ("mask", "");
} }
/**/
// Override with default.project, if not specified. // Override with default.project, if not specified.
if (task.getAttribute ("project") == "") if (task.getAttribute ("project") == "")
task.setAttribute ("project", conf.get ("default.project", "")); task.setAttribute ("project", conf.get ("default.project", ""));
@ -79,18 +79,20 @@ void handleAdd (TDB& tdb, T& task, Config& conf)
if (validPriority (defaultPriority)) if (validPriority (defaultPriority))
task.setAttribute ("priority", defaultPriority); task.setAttribute ("priority", defaultPriority);
} }
/**/
// Disallow blank descriptions.
if (task.getDescription () == "") if (task.getDescription () == "")
throw std::string ("Cannot add a blank task."); throw std::string ("Cannot add a task that is blank, or contains <CR> or <LF> characters.");
if (!tdb.addT (task)) if (!tdb.addT (task))
throw std::string ("Could not create new task."); throw std::string ("Could not create new task.");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void handleProjects (TDB& tdb, T& task, Config& conf) std::string handleProjects (TDB& tdb, T& task, Config& conf)
{ {
std::stringstream out;
// Get all the tasks, including deleted ones. // Get all the tasks, including deleted ones.
std::vector <T> tasks; std::vector <T> tasks;
tdb.pendingT (tasks); tdb.pendingT (tasks);
@ -127,7 +129,7 @@ void handleProjects (TDB& tdb, T& task, Config& conf)
table.addCell (row, 1, i->second); table.addCell (row, 1, i->second);
} }
std::cout << optionalBlankLine (conf) out << optionalBlankLine (conf)
<< table.render () << table.render ()
<< optionalBlankLine (conf) << optionalBlankLine (conf)
<< unique.size () << unique.size ()
@ -135,13 +137,17 @@ void handleProjects (TDB& tdb, T& task, Config& conf)
<< std::endl; << std::endl;
} }
else else
std::cout << "No projects." out << "No projects."
<< std::endl; << std::endl;
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void handleTags (TDB& tdb, T& task, Config& conf) std::string handleTags (TDB& tdb, T& task, Config& conf)
{ {
std::stringstream out;
// Get all the tasks. // Get all the tasks.
std::vector <T> tasks; std::vector <T> tasks;
tdb.pendingT (tasks); tdb.pendingT (tasks);
@ -166,20 +172,23 @@ void handleTags (TDB& tdb, T& task, Config& conf)
std::cout << i->first << std::endl; std::cout << i->first << std::endl;
if (unique.size ()) if (unique.size ())
std::cout << optionalBlankLine (conf) out << optionalBlankLine (conf)
<< unique.size () << unique.size ()
<< (unique.size () == 1 ? " tag" : " tags") << (unique.size () == 1 ? " tag" : " tags")
<< std::endl; << std::endl;
else else
std::cout << "No tags." out << "No tags."
<< std::endl; << std::endl;
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// If a task is deleted, but is still in the pending file, then it may be // If a task is deleted, but is still in the pending file, then it may be
// undeleted simply by changing it's status. // undeleted simply by changing it's status.
void handleUndelete (TDB& tdb, T& task, Config& conf) std::string handleUndelete (TDB& tdb, T& task, Config& conf)
{ {
std::stringstream out;
std::vector <T> all; std::vector <T> all;
tdb.allPendingT (all); tdb.allPendingT (all);
@ -193,8 +202,8 @@ void handleUndelete (TDB& tdb, T& task, Config& conf)
{ {
if (it->getAttribute ("recur") != "") if (it->getAttribute ("recur") != "")
{ {
std::cout << "Task does not support 'undelete' for recurring tasks." << std::endl; out << "Task does not support 'undelete' for recurring tasks." << std::endl;
return; return out.str ();
} }
T restored (*it); T restored (*it);
@ -202,27 +211,31 @@ void handleUndelete (TDB& tdb, T& task, Config& conf)
restored.removeAttribute ("end"); restored.removeAttribute ("end");
tdb.modifyT (restored); tdb.modifyT (restored);
std::cout << "Task " << id << " successfully undeleted." << std::endl; out << "Task " << id << " successfully undeleted." << std::endl;
return; return out.str ();
} }
else else
{ {
std::cout << "Task " << id << " is not deleted - therefore cannot undelete." << std::endl; out << "Task " << id << " is not deleted - therefore cannot undelete." << std::endl;
return; return out.str ();
} }
} }
} }
std::cout << "Task " << id out << "Task " << id
<< " not found - tasks can only be reliably undeleted if the undelete" << std::endl << " not found - tasks can only be reliably undeleted if the undelete" << std::endl
<< "command is run immediately after the errant delete command." << std::endl; << "command is run immediately after the errant delete command." << std::endl;
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// If a task is done, but is still in the pending file, then it may be undone // If a task is done, but is still in the pending file, then it may be undone
// simply by changing it's status. // simply by changing it's status.
void handleUndo (TDB& tdb, T& task, Config& conf) std::string handleUndo (TDB& tdb, T& task, Config& conf)
{ {
std::stringstream out;
std::vector <T> all; std::vector <T> all;
tdb.allPendingT (all); tdb.allPendingT (all);
@ -235,35 +248,36 @@ void handleUndo (TDB& tdb, T& task, Config& conf)
if (it->getStatus () == T::completed) if (it->getStatus () == T::completed)
{ {
if (it->getAttribute ("recur") != "") if (it->getAttribute ("recur") != "")
{ return std::string ("Task does not support 'undo' for recurring tasks.\n");
std::cout << "Task does not support 'undo' for recurring tasks." << std::endl;
return;
}
T restored (*it); T restored (*it);
restored.setStatus (T::pending); restored.setStatus (T::pending);
restored.removeAttribute ("end"); restored.removeAttribute ("end");
tdb.modifyT (restored); tdb.modifyT (restored);
std::cout << "Task " << id << " successfully undone." << std::endl; out << "Task " << id << " successfully undone." << std::endl;
return; return out.str ();
} }
else else
{ {
std::cout << "Task " << id << " is not done - therefore cannot be undone." << std::endl; out << "Task " << id << " is not done - therefore cannot be undone." << std::endl;
return; return out.str ();
} }
} }
} }
std::cout << "Task " << id out << "Task " << id
<< " not found - tasks can only be reliably undone if the undo" << std::endl << " not found - tasks can only be reliably undone if the undo" << std::endl
<< "command is run immediately after the errant done command." << std::endl; << "command is run immediately after the errant done command." << std::endl;
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void handleVersion (Config& conf) std::string handleVersion (Config& conf)
{ {
std::stringstream out;
// Determine window size, and set table accordingly. // Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80); int width = conf.get ("defaultwidth", 80);
#ifdef HAVE_LIBNCURSES #ifdef HAVE_LIBNCURSES
@ -329,7 +343,7 @@ void handleVersion (Config& conf)
} }
} }
std::cout << "Copyright (C) 2006 - 2008, P. Beckingham." out << "Copyright (C) 2006 - 2008, P. Beckingham."
<< std::endl << std::endl
<< (conf.get ("color", true) ? Text::colorize (Text::bold, Text::nocolor, PACKAGE) : PACKAGE) << (conf.get ("color", true) ? Text::colorize (Text::bold, Text::nocolor, PACKAGE) : PACKAGE)
<< " " << " "
@ -345,24 +359,26 @@ void handleVersion (Config& conf)
// ensure everything is properly installed. // ensure everything is properly installed.
if (all.size () == 0) if (all.size () == 0)
std::cout << "Configuration error: .taskrc contains no entries" out << "Configuration error: .taskrc contains no entries"
<< std::endl; << std::endl;
else else
{ {
if (conf.get ("data.location") == "") if (conf.get ("data.location") == "")
std::cout << "Configuration error: data.location not specified in .taskrc " out << "Configuration error: data.location not specified in .taskrc "
"file." "file."
<< std::endl; << std::endl;
if (access (expandPath (conf.get ("data.location")).c_str (), X_OK)) if (access (expandPath (conf.get ("data.location")).c_str (), X_OK))
std::cout << "Configuration error: data.location contains a directory name" out << "Configuration error: data.location contains a directory name"
" that doesn't exist, or is unreadable." " that doesn't exist, or is unreadable."
<< std::endl; << std::endl;
} }
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void handleDelete (TDB& tdb, T& task, Config& conf) std::string handleDelete (TDB& tdb, T& task, Config& conf)
{ {
if (conf.get ("confirmation") != "yes" || confirm ("Permanently delete task?")) if (conf.get ("confirmation") != "yes" || confirm ("Permanently delete task?"))
{ {
@ -386,7 +402,7 @@ void handleDelete (TDB& tdb, T& task, Config& conf)
sibling->getUUID () == parent) sibling->getUUID () == parent)
tdb.deleteT (*sibling); tdb.deleteT (*sibling);
return; return std::string ("");
} }
else else
{ {
@ -394,7 +410,7 @@ void handleDelete (TDB& tdb, T& task, Config& conf)
t->setStatus (T::deleted); t->setStatus (T::deleted);
updateRecurrenceMask (tdb, all, *t); updateRecurrenceMask (tdb, all, *t);
tdb.deleteT (*t); tdb.deleteT (*t);
return; return std::string ("");
} }
} }
else else
@ -405,11 +421,13 @@ void handleDelete (TDB& tdb, T& task, Config& conf)
} }
} }
else else
std::cout << "Task not deleted." << std::endl; return std::string ("Task not deleted.\n");
return std::string ("");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void handleStart (TDB& tdb, T& task, Config& conf) std::string handleStart (TDB& tdb, T& task, Config& conf)
{ {
std::vector <T> all; std::vector <T> all;
tdb.pendingT (all); tdb.pendingT (all);
@ -431,18 +449,23 @@ void handleStart (TDB& tdb, T& task, Config& conf)
tdb.modifyT (original); tdb.modifyT (original);
nag (tdb, task, conf); nag (tdb, task, conf);
return; return std::string ("");
} }
else else
std::cout << "Task " << task.getId () << " already started." << std::endl; {
std::stringstream out;
out << "Task " << task.getId () << " already started." << std::endl;
return out.str ();
}
} }
} }
throw std::string ("Task not found."); throw std::string ("Task not found.");
return std::string (""); // To satisfy gcc.
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void handleStop (TDB& tdb, T& task, Config& conf) std::string handleStop (TDB& tdb, T& task, Config& conf)
{ {
std::vector <T> all; std::vector <T> all;
tdb.pendingT (all); tdb.pendingT (all);
@ -461,14 +484,19 @@ void handleStop (TDB& tdb, T& task, Config& conf)
tdb.modifyT (original); tdb.modifyT (original);
nag (tdb, task, conf); nag (tdb, task, conf);
return; return std::string ("");
} }
else else
std::cout << "Task " << task.getId () << " not started." << std::endl; {
std::stringstream out;
out << "Task " << task.getId () << " not started." << std::endl;
return out.str ();
}
} }
} }
throw std::string ("Task not found."); throw std::string ("Task not found.");
return std::string (""); // To satisfy gcc.
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -627,11 +655,13 @@ void handleModify (TDB& tdb, T& task, Config& conf)
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void handleColor (Config& conf) std::string handleColor (Config& conf)
{ {
std::stringstream out;
if (conf.get ("color", true)) if (conf.get ("color", true))
{ {
std::cout << optionalBlankLine (conf) << "Foreground" << std::endl out << optionalBlankLine (conf) << "Foreground" << std::endl
<< " " << " "
<< Text::colorize (Text::bold, Text::nocolor, "bold") << " " << Text::colorize (Text::bold, Text::nocolor, "bold") << " "
<< Text::colorize (Text::underline, Text::nocolor, "underline") << " " << Text::colorize (Text::underline, Text::nocolor, "underline") << " "
@ -706,8 +736,10 @@ void handleColor (Config& conf)
} }
else else
{ {
std::cout << "Color is currently turned off in your .taskrc file." << std::endl; out << "Color is currently turned off in your .taskrc file." << std::endl;
} }
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View file

@ -284,10 +284,21 @@ static bool validTag (const std::string& input)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static bool validDescription (const std::string& input) static bool validDescription (const std::string& input)
{ {
if (input.length () > 0) /*
if (input.length () > 0 &&
input.find ("\r") == std::string::npos &&
input.find ("\f") == std::string::npos &&
input.find ("\n") == std::string::npos)
return true; return true;
return false; return false;
*/
if (input.length () == 0) return false;
if (input.find ("\r") != std::string::npos) return false;
if (input.find ("\f") != std::string::npos) return false;
if (input.find ("\n") != std::string::npos) return false;
return true;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View file

@ -26,6 +26,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <sstream>
#include <fstream> #include <fstream>
#include <sys/types.h> #include <sys/types.h>
#include <stdio.h> #include <stdio.h>
@ -110,8 +111,10 @@ void filter (std::vector<T>& all, T& task)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Successively apply filters based on the task object built from the command // Successively apply filters based on the task object built from the command
// line. Tasks that match all the specified criteria are listed. // line. Tasks that match all the specified criteria are listed.
void handleList (TDB& tdb, T& task, Config& conf) std::string handleList (TDB& tdb, T& task, Config& conf)
{ {
std::stringstream out;
// Determine window size, and set table accordingly. // Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80); int width = conf.get ("defaultwidth", 80);
#ifdef HAVE_LIBNCURSES #ifdef HAVE_LIBNCURSES
@ -124,7 +127,6 @@ void handleList (TDB& tdb, T& task, Config& conf)
#endif #endif
// Get the pending tasks. // Get the pending tasks.
tdb.gc ();
std::vector <T> tasks; std::vector <T> tasks;
tdb.allPendingT (tasks); tdb.allPendingT (tasks);
handleRecurrence (tdb, tasks); handleRecurrence (tdb, tasks);
@ -242,23 +244,27 @@ void handleList (TDB& tdb, T& task, Config& conf)
} }
if (table.rowCount ()) if (table.rowCount ())
std::cout << optionalBlankLine (conf) out << optionalBlankLine (conf)
<< table.render () << table.render ()
<< optionalBlankLine (conf) << optionalBlankLine (conf)
<< table.rowCount () << table.rowCount ()
<< (table.rowCount () == 1 ? " task" : " tasks") << (table.rowCount () == 1 ? " task" : " tasks")
<< std::endl; << std::endl;
else else
std::cout << "No matches." out << "No matches."
<< std::endl; << std::endl;
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Successively apply filters based on the task object built from the command // 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 // line. Tasks that match all the specified criteria are listed. Show a narrow
// list that works better on mobile devices. // list that works better on mobile devices.
void handleSmallList (TDB& tdb, T& task, Config& conf) std::string handleSmallList (TDB& tdb, T& task, Config& conf)
{ {
std::stringstream out;
// Determine window size, and set table accordingly. // Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80); int width = conf.get ("defaultwidth", 80);
#ifdef HAVE_LIBNCURSES #ifdef HAVE_LIBNCURSES
@ -271,7 +277,6 @@ void handleSmallList (TDB& tdb, T& task, Config& conf)
#endif #endif
// Get the pending tasks. // Get the pending tasks.
tdb.gc ();
std::vector <T> tasks; std::vector <T> tasks;
tdb.allPendingT (tasks); tdb.allPendingT (tasks);
handleRecurrence (tdb, tasks); handleRecurrence (tdb, tasks);
@ -371,22 +376,26 @@ void handleSmallList (TDB& tdb, T& task, Config& conf)
} }
if (table.rowCount ()) if (table.rowCount ())
std::cout << optionalBlankLine (conf) out << optionalBlankLine (conf)
<< table.render () << table.render ()
<< optionalBlankLine (conf) << optionalBlankLine (conf)
<< table.rowCount () << table.rowCount ()
<< (table.rowCount () == 1 ? " task" : " tasks") << (table.rowCount () == 1 ? " task" : " tasks")
<< std::endl; << std::endl;
else else
std::cout << "No matches." out << "No matches."
<< std::endl; << std::endl;
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Successively apply filters based on the task object built from the command // Successively apply filters based on the task object built from the command
// line. Tasks that match all the specified criteria are listed. // line. Tasks that match all the specified criteria are listed.
void handleCompleted (TDB& tdb, T& task, Config& conf) std::string handleCompleted (TDB& tdb, T& task, Config& conf)
{ {
std::stringstream out;
// Determine window size, and set table accordingly. // Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80); int width = conf.get ("defaultwidth", 80);
#ifdef HAVE_LIBNCURSES #ifdef HAVE_LIBNCURSES
@ -399,7 +408,6 @@ void handleCompleted (TDB& tdb, T& task, Config& conf)
#endif #endif
// Get the pending tasks. // Get the pending tasks.
tdb.gc ();
std::vector <T> tasks; std::vector <T> tasks;
tdb.completedT (tasks); tdb.completedT (tasks);
filter (tasks, task); filter (tasks, task);
@ -459,21 +467,25 @@ void handleCompleted (TDB& tdb, T& task, Config& conf)
} }
if (table.rowCount ()) if (table.rowCount ())
std::cout << optionalBlankLine (conf) out << optionalBlankLine (conf)
<< table.render () << table.render ()
<< optionalBlankLine (conf) << optionalBlankLine (conf)
<< table.rowCount () << table.rowCount ()
<< (table.rowCount () == 1 ? " task" : " tasks") << (table.rowCount () == 1 ? " task" : " tasks")
<< std::endl; << std::endl;
else else
std::cout << "No matches." out << "No matches."
<< std::endl; << std::endl;
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Display all information for the given task. // Display all information for the given task.
void handleInfo (TDB& tdb, T& task, Config& conf) std::string handleInfo (TDB& tdb, T& task, Config& conf)
{ {
std::stringstream out;
// Determine window size, and set table accordingly. // Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80); int width = conf.get ("defaultwidth", 80);
#ifdef HAVE_LIBNCURSES #ifdef HAVE_LIBNCURSES
@ -657,18 +669,22 @@ void handleInfo (TDB& tdb, T& task, Config& conf)
} }
if (table.rowCount ()) if (table.rowCount ())
std::cout << optionalBlankLine (conf) out << optionalBlankLine (conf)
<< table.render () << table.render ()
<< std::endl; << std::endl;
else else
std::cout << "No matches." << std::endl; out << "No matches." << std::endl;
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Successively apply filters based on the task object built from the command // Successively apply filters based on the task object built from the command
// line. Tasks that match all the specified criteria are listed. // line. Tasks that match all the specified criteria are listed.
void handleLongList (TDB& tdb, T& task, Config& conf) std::string handleLongList (TDB& tdb, T& task, Config& conf)
{ {
std::stringstream out;
// Determine window size, and set table accordingly. // Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80); int width = conf.get ("defaultwidth", 80);
#ifdef HAVE_LIBNCURSES #ifdef HAVE_LIBNCURSES
@ -681,7 +697,6 @@ void handleLongList (TDB& tdb, T& task, Config& conf)
#endif #endif
// Get all the tasks. // Get all the tasks.
tdb.gc ();
std::vector <T> tasks; std::vector <T> tasks;
tdb.allPendingT (tasks); tdb.allPendingT (tasks);
handleRecurrence (tdb, tasks); handleRecurrence (tdb, tasks);
@ -824,24 +839,27 @@ void handleLongList (TDB& tdb, T& task, Config& conf)
} }
if (table.rowCount ()) if (table.rowCount ())
std::cout << optionalBlankLine (conf) out << optionalBlankLine (conf)
<< table.render () << table.render ()
<< optionalBlankLine (conf) << optionalBlankLine (conf)
<< table.rowCount () << table.rowCount ()
<< (table.rowCount () == 1 ? " task" : " tasks") << (table.rowCount () == 1 ? " task" : " tasks")
<< std::endl; << std::endl;
else else
std::cout << "No matches." << std::endl; out << "No matches." << std::endl;
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Project Tasks Avg Age Status // Project Tasks Avg Age Status
// A 12 13d XXXXXXXX------ // A 12 13d XXXXXXXX------
// B 109 3d 12h XX------------ // B 109 3d 12h XX------------
void handleReportSummary (TDB& tdb, T& task, Config& conf) std::string handleReportSummary (TDB& tdb, T& task, Config& conf)
{ {
std::stringstream out;
// Generate unique list of project names. // Generate unique list of project names.
tdb.gc ();
std::map <std::string, bool> allProjects; std::map <std::string, bool> allProjects;
std::vector <T> pending; std::vector <T> pending;
tdb.allPendingT (pending); tdb.allPendingT (pending);
@ -981,14 +999,16 @@ void handleReportSummary (TDB& tdb, T& task, Config& conf)
} }
if (table.rowCount ()) if (table.rowCount ())
std::cout << optionalBlankLine (conf) out << optionalBlankLine (conf)
<< table.render () << table.render ()
<< optionalBlankLine (conf) << optionalBlankLine (conf)
<< table.rowCount () << table.rowCount ()
<< (table.rowCount () == 1 ? " project" : " projects") << (table.rowCount () == 1 ? " project" : " projects")
<< std::endl; << std::endl;
else else
std::cout << "No projects." << std::endl; out << "No projects." << std::endl;
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -1010,10 +1030,11 @@ void handleReportSummary (TDB& tdb, T& task, Config& conf)
// //
// Make the "three" tasks a configurable number // Make the "three" tasks a configurable number
// //
void handleReportNext (TDB& tdb, T& task, Config& conf) std::string handleReportNext (TDB& tdb, T& task, Config& conf)
{ {
std::stringstream out;
// Load all pending. // Load all pending.
tdb.gc ();
std::vector <T> pending; std::vector <T> pending;
tdb.allPendingT (pending); tdb.allPendingT (pending);
handleRecurrence (tdb, pending); handleRecurrence (tdb, pending);
@ -1034,8 +1055,6 @@ void handleReportNext (TDB& tdb, T& task, Config& conf)
} }
#endif #endif
tdb.gc ();
// Get the pending tasks. // Get the pending tasks.
std::vector <T> tasks; std::vector <T> tasks;
tdb.pendingT (tasks); tdb.pendingT (tasks);
@ -1151,15 +1170,17 @@ void handleReportNext (TDB& tdb, T& task, Config& conf)
} }
if (table.rowCount ()) if (table.rowCount ())
std::cout << optionalBlankLine (conf) out << optionalBlankLine (conf)
<< table.render () << table.render ()
<< optionalBlankLine (conf) << optionalBlankLine (conf)
<< table.rowCount () << table.rowCount ()
<< (table.rowCount () == 1 ? " task" : " tasks") << (table.rowCount () == 1 ? " task" : " tasks")
<< std::endl; << std::endl;
else else
std::cout << "No matches." out << "No matches."
<< std::endl; << std::endl;
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -1184,15 +1205,16 @@ time_t monthlyEpoch (const std::string& date)
return 0; return 0;
} }
void handleReportHistory (TDB& tdb, T& task, Config& conf) std::string handleReportHistory (TDB& tdb, T& task, Config& conf)
{ {
std::stringstream out;
std::map <time_t, int> groups; std::map <time_t, int> groups;
std::map <time_t, int> addedGroup; std::map <time_t, int> addedGroup;
std::map <time_t, int> completedGroup; std::map <time_t, int> completedGroup;
std::map <time_t, int> deletedGroup; std::map <time_t, int> deletedGroup;
// Scan the pending tasks. // Scan the pending tasks.
tdb.gc ();
std::vector <T> pending; std::vector <T> pending;
tdb.allPendingT (pending); tdb.allPendingT (pending);
handleRecurrence (tdb, pending); handleRecurrence (tdb, pending);
@ -1360,16 +1382,20 @@ void handleReportHistory (TDB& tdb, T& task, Config& conf)
} }
if (table.rowCount ()) if (table.rowCount ())
std::cout << optionalBlankLine (conf) out << optionalBlankLine (conf)
<< table.render () << table.render ()
<< std::endl; << std::endl;
else else
std::cout << "No tasks." << std::endl; out << "No tasks." << std::endl;
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void handleReportGHistory (TDB& tdb, T& task, Config& conf) std::string handleReportGHistory (TDB& tdb, T& task, Config& conf)
{ {
std::stringstream out;
// Determine window size, and set table accordingly. // Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80); int width = conf.get ("defaultwidth", 80);
#ifdef HAVE_LIBNCURSES #ifdef HAVE_LIBNCURSES
@ -1388,7 +1414,6 @@ void handleReportGHistory (TDB& tdb, T& task, Config& conf)
std::map <time_t, int> deletedGroup; std::map <time_t, int> deletedGroup;
// Scan the pending tasks. // Scan the pending tasks.
tdb.gc ();
std::vector <T> pending; std::vector <T> pending;
tdb.allPendingT (pending); tdb.allPendingT (pending);
handleRecurrence (tdb, pending); handleRecurrence (tdb, pending);
@ -1583,12 +1608,12 @@ void handleReportGHistory (TDB& tdb, T& task, Config& conf)
if (table.rowCount ()) if (table.rowCount ())
{ {
std::cout << optionalBlankLine (conf) out << optionalBlankLine (conf)
<< table.render () << table.render ()
<< std::endl; << std::endl;
if (conf.get ("color", true)) if (conf.get ("color", true))
std::cout << "Legend: " out << "Legend: "
<< Text::colorize (Text::black, Text::on_red, "added") << Text::colorize (Text::black, Text::on_red, "added")
<< ", " << ", "
<< Text::colorize (Text::black, Text::on_green, "completed") << Text::colorize (Text::black, Text::on_green, "completed")
@ -1597,10 +1622,12 @@ void handleReportGHistory (TDB& tdb, T& task, Config& conf)
<< optionalBlankLine (conf) << optionalBlankLine (conf)
<< std::endl; << std::endl;
else else
std::cout << "Legend: + added, X completed, - deleted" << std::endl; out << "Legend: + added, X completed, - deleted" << std::endl;
} }
else else
std::cout << "No tasks." << std::endl; out << "No tasks." << std::endl;
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -1728,10 +1755,11 @@ std::string renderMonths (
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void handleReportCalendar (TDB& tdb, T& task, Config& conf) std::string handleReportCalendar (TDB& tdb, T& task, Config& conf)
{ {
std::stringstream out;
// Load all the pending tasks. // Load all the pending tasks.
tdb.gc ();
std::vector <T> pending; std::vector <T> pending;
tdb.allPendingT (pending); tdb.allPendingT (pending);
handleRecurrence (tdb, pending); handleRecurrence (tdb, pending);
@ -1760,7 +1788,7 @@ void handleReportCalendar (TDB& tdb, T& task, Config& conf)
int mTo = newest.month (); int mTo = newest.month ();
int yTo = newest.year (); int yTo = newest.year ();
std::cout << std::endl; out << std::endl;
std::string output; std::string output;
int monthsPerLine = (conf.get ("monthsperline", 1)); int monthsPerLine = (conf.get ("monthsperline", 1));
@ -1777,7 +1805,7 @@ void handleReportCalendar (TDB& tdb, T& task, Config& conf)
int left = (18 - month.length ()) / 2 + 1; int left = (18 - month.length ()) / 2 + 1;
int right = 18 - left - month.length (); int right = 18 - left - month.length ();
std::cout << std::setw (left) << ' ' out << std::setw (left) << ' '
<< month << month
<< ' ' << ' '
<< nextY << nextY
@ -1790,7 +1818,7 @@ void handleReportCalendar (TDB& tdb, T& task, Config& conf)
} }
} }
std::cout << std::endl out << std::endl
<< optionalBlankLine (conf) << optionalBlankLine (conf)
<< renderMonths (mFrom, yFrom, today, pending, conf) << renderMonths (mFrom, yFrom, today, pending, conf)
<< std::endl; << std::endl;
@ -1803,7 +1831,7 @@ void handleReportCalendar (TDB& tdb, T& task, Config& conf)
} }
} }
std::cout << "Legend: " out << "Legend: "
<< Text::colorize (Text::cyan, Text::nocolor, "today") << Text::colorize (Text::cyan, Text::nocolor, "today")
<< ", " << ", "
<< Text::colorize (Text::black, Text::on_yellow, "due") << Text::colorize (Text::black, Text::on_yellow, "due")
@ -1812,11 +1840,15 @@ void handleReportCalendar (TDB& tdb, T& task, Config& conf)
<< "." << "."
<< optionalBlankLine (conf) << optionalBlankLine (conf)
<< std::endl; << std::endl;
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void handleReportActive (TDB& tdb, T& task, Config& conf) std::string handleReportActive (TDB& tdb, T& task, Config& conf)
{ {
std::stringstream out;
// Determine window size, and set table accordingly. // Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80); int width = conf.get ("defaultwidth", 80);
#ifdef HAVE_LIBNCURSES #ifdef HAVE_LIBNCURSES
@ -1829,7 +1861,6 @@ void handleReportActive (TDB& tdb, T& task, Config& conf)
#endif #endif
// Get all the tasks. // Get all the tasks.
tdb.gc ();
std::vector <T> tasks; std::vector <T> tasks;
tdb.pendingT (tasks); tdb.pendingT (tasks);
filter (tasks, task); filter (tasks, task);
@ -1922,19 +1953,23 @@ void handleReportActive (TDB& tdb, T& task, Config& conf)
} }
if (table.rowCount ()) if (table.rowCount ())
std::cout << optionalBlankLine (conf) out << optionalBlankLine (conf)
<< table.render () << table.render ()
<< optionalBlankLine (conf) << optionalBlankLine (conf)
<< table.rowCount () << table.rowCount ()
<< (table.rowCount () == 1 ? " task" : " tasks") << (table.rowCount () == 1 ? " task" : " tasks")
<< std::endl; << std::endl;
else else
std::cout << "No active tasks." << std::endl; out << "No active tasks." << std::endl;
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void handleReportOverdue (TDB& tdb, T& task, Config& conf) std::string handleReportOverdue (TDB& tdb, T& task, Config& conf)
{ {
std::stringstream out;
// Determine window size, and set table accordingly. // Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80); int width = conf.get ("defaultwidth", 80);
#ifdef HAVE_LIBNCURSES #ifdef HAVE_LIBNCURSES
@ -2029,21 +2064,25 @@ void handleReportOverdue (TDB& tdb, T& task, Config& conf)
} }
if (table.rowCount ()) if (table.rowCount ())
std::cout << optionalBlankLine (conf) out << optionalBlankLine (conf)
<< table.render () << table.render ()
<< optionalBlankLine (conf) << optionalBlankLine (conf)
<< table.rowCount () << table.rowCount ()
<< (table.rowCount () == 1 ? " task" : " tasks") << (table.rowCount () == 1 ? " task" : " tasks")
<< std::endl; << std::endl;
else else
std::cout << "No overdue tasks." << std::endl; out << "No overdue tasks." << std::endl;
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Successively apply filters based on the task object built from the command // Successively apply filters based on the task object built from the command
// line. Tasks that match all the specified criteria are listed. // line. Tasks that match all the specified criteria are listed.
void handleReportOldest (TDB& tdb, T& task, Config& conf) std::string handleReportOldest (TDB& tdb, T& task, Config& conf)
{ {
std::stringstream out;
// Determine window size, and set table accordingly. // Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80); int width = conf.get ("defaultwidth", 80);
#ifdef HAVE_LIBNCURSES #ifdef HAVE_LIBNCURSES
@ -2056,7 +2095,6 @@ void handleReportOldest (TDB& tdb, T& task, Config& conf)
#endif #endif
// Get the pending tasks. // Get the pending tasks.
tdb.gc ();
std::vector <T> tasks; std::vector <T> tasks;
tdb.allPendingT (tasks); tdb.allPendingT (tasks);
handleRecurrence (tdb, tasks); handleRecurrence (tdb, tasks);
@ -2173,22 +2211,26 @@ void handleReportOldest (TDB& tdb, T& task, Config& conf)
} }
if (table.rowCount ()) if (table.rowCount ())
std::cout << optionalBlankLine (conf) out << optionalBlankLine (conf)
<< table.render () << table.render ()
<< optionalBlankLine (conf) << optionalBlankLine (conf)
<< table.rowCount () << table.rowCount ()
<< (table.rowCount () == 1 ? " task" : " tasks") << (table.rowCount () == 1 ? " task" : " tasks")
<< std::endl; << std::endl;
else else
std::cout << "No matches." out << "No matches."
<< std::endl; << std::endl;
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Successively apply filters based on the task object built from the command // Successively apply filters based on the task object built from the command
// line. Tasks that match all the specified criteria are listed. // line. Tasks that match all the specified criteria are listed.
void handleReportNewest (TDB& tdb, T& task, Config& conf) std::string handleReportNewest (TDB& tdb, T& task, Config& conf)
{ {
std::stringstream out;
// Determine window size, and set table accordingly. // Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80); int width = conf.get ("defaultwidth", 80);
#ifdef HAVE_LIBNCURSES #ifdef HAVE_LIBNCURSES
@ -2201,7 +2243,6 @@ void handleReportNewest (TDB& tdb, T& task, Config& conf)
#endif #endif
// Get the pending tasks. // Get the pending tasks.
tdb.gc ();
std::vector <T> tasks; std::vector <T> tasks;
tdb.allPendingT (tasks); tdb.allPendingT (tasks);
handleRecurrence (tdb, tasks); handleRecurrence (tdb, tasks);
@ -2319,21 +2360,25 @@ void handleReportNewest (TDB& tdb, T& task, Config& conf)
} }
if (table.rowCount ()) if (table.rowCount ())
std::cout << optionalBlankLine (conf) out << optionalBlankLine (conf)
<< table.render () << table.render ()
<< optionalBlankLine (conf) << optionalBlankLine (conf)
<< table.rowCount () << table.rowCount ()
<< (table.rowCount () == 1 ? " task" : " tasks") << (table.rowCount () == 1 ? " task" : " tasks")
<< std::endl; << std::endl;
else else
std::cout << "No matches." out << "No matches."
<< std::endl; << std::endl;
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void handleReportStats (TDB& tdb, T& task, Config& conf) std::string handleReportStats (TDB& tdb, T& task, Config& conf)
{ {
std::stringstream out;
// Get all the tasks. // Get all the tasks.
std::vector <T> tasks; std::vector <T> tasks;
tdb.allT (tasks); tdb.allT (tasks);
@ -2380,7 +2425,7 @@ void handleReportStats (TDB& tdb, T& task, Config& conf)
if (tags.size ()) ++taggedT; if (tags.size ()) ++taggedT;
} }
std::cout << "Pending " << pendingT << std::endl out << "Pending " << pendingT << std::endl
<< "Recurring " << recurringT << std::endl << "Recurring " << recurringT << std::endl
<< "Completed " << completedT << std::endl << "Completed " << completedT << std::endl
<< "Deleted " << deletedT << std::endl << "Deleted " << deletedT << std::endl
@ -2389,31 +2434,33 @@ void handleReportStats (TDB& tdb, T& task, Config& conf)
if (tasks.size ()) if (tasks.size ())
{ {
Date e (earliest); Date e (earliest);
std::cout << "Oldest task " << e.toString (conf.get ("dateformat", "m/d/Y")) << std::endl; out << "Oldest task " << e.toString (conf.get ("dateformat", "m/d/Y")) << std::endl;
Date l (latest); Date l (latest);
std::cout << "Newest task " << l.toString (conf.get ("dateformat", "m/d/Y")) << std::endl; out << "Newest task " << l.toString (conf.get ("dateformat", "m/d/Y")) << std::endl;
std::cout << "Task used for " << formatSeconds (latest - earliest) << std::endl; out << "Task used for " << formatSeconds (latest - earliest) << std::endl;
} }
if (totalT) if (totalT)
std::cout << "Task added every " << formatSeconds ((latest - earliest) / totalT) << std::endl; out << "Task added every " << formatSeconds ((latest - earliest) / totalT) << std::endl;
if (completedT) if (completedT)
std::cout << "Task completed every " << formatSeconds ((latest - earliest) / completedT) << std::endl; out << "Task completed every " << formatSeconds ((latest - earliest) / completedT) << std::endl;
if (deletedT) if (deletedT)
std::cout << "Task deleted every " << formatSeconds ((latest - earliest) / deletedT) << std::endl; out << "Task deleted every " << formatSeconds ((latest - earliest) / deletedT) << std::endl;
if (pendingT || completedT) if (pendingT || completedT)
std::cout << "Average time pending " out << "Average time pending "
<< formatSeconds ((int) ((daysPending / (pendingT + completedT)) * 86400)) << formatSeconds ((int) ((daysPending / (pendingT + completedT)) * 86400))
<< std::endl; << std::endl;
if (totalT) if (totalT)
{ {
std::cout << "Average desc length " << (int) (descLength / totalT) << " characters" << std::endl; out << "Average desc length " << (int) (descLength / totalT) << " characters" << std::endl;
std::cout << "Tasks tagged " << std::setprecision (3) << (100.0 * taggedT / totalT) << "%" << std::endl; out << "Tasks tagged " << std::setprecision (3) << (100.0 * taggedT / totalT) << "%" << std::endl;
} }
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View file

@ -319,18 +319,18 @@ int main (int argc, char** argv)
tdb.onChange (&onChangeCallback); tdb.onChange (&onChangeCallback);
} }
runTaskCommand (argc, argv, tdb, conf); std::cout << runTaskCommand (argc, argv, tdb, conf);
} }
catch (std::string& error) catch (std::string& error)
{ {
std::cout << error << std::endl; std::cerr << error << std::endl;
return -1; return -1;
} }
catch (...) catch (...)
{ {
std::cout << "Unknown error." << std::endl; std::cerr << "Unknown error." << std::endl;
return -2; return -2;
} }
@ -679,16 +679,14 @@ void onChangeCallback ()
{ {
if (gConf && gTdb) if (gConf && gTdb)
{ {
gConf->set ("curses", "off");
gConf->set ("color", "off");
// Determine if shadow file is enabled. // Determine if shadow file is enabled.
std::string shadowFile = expandPath (gConf->get ("shadow.file")); std::string shadowFile = expandPath (gConf->get ("shadow.file"));
if (shadowFile != "") if (shadowFile != "")
{ {
// Capture std::cout for the shadow file. std::string oldCurses = gConf->get ("curses");
std::ofstream shadow (shadowFile.c_str ()); std::string oldColor = gConf->get ("color");
std::streambuf* original = std::cout.rdbuf (shadow.rdbuf ()); gConf->set ("curses", "off");
gConf->set ("color", "off");
// Run report. Use shadow.command, using default.command as a fallback // Run report. Use shadow.command, using default.command as a fallback
// with "list" as a default. // with "list" as a default.
@ -696,13 +694,26 @@ void onChangeCallback ()
gConf->get ("default.command", "list")); gConf->get ("default.command", "list"));
std::vector <std::string> args; std::vector <std::string> args;
split (args, command, ' '); split (args, command, ' ');
runTaskCommand (args, *gTdb, *gConf); std::string result = runTaskCommand (args, *gTdb, *gConf);
// Restore std::cout. std::ofstream out (shadowFile.c_str ());
std::cout.rdbuf (original); if (out.good ())
{
out << result;
out.close ();
} }
else else
throw std::string ("Could not write to '") + shadowFile + "'."; throw std::string ("Could not write file '") + shadowFile + "'";
gConf->set ("curses", oldCurses);
gConf->set ("color", oldColor);
}
else
throw std::string ("No specified shadow 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;
} }
else else
throw std::string ("Internal error (TDB/Config)."); throw std::string ("Internal error (TDB/Config).");
@ -720,24 +731,26 @@ void onChangeCallback ()
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void runTaskCommand ( std::string runTaskCommand (
int argc, int argc,
char** argv, char** argv,
TDB& tdb, TDB& tdb,
Config& conf) Config& conf,
bool gc /* = true */)
{ {
std::vector <std::string> args; std::vector <std::string> args;
for (int i = 1; i < argc; ++i) for (int i = 1; i < argc; ++i)
args.push_back (argv[i]); args.push_back (argv[i]);
runTaskCommand (args, tdb, conf); return runTaskCommand (args, tdb, conf, gc);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void runTaskCommand ( std::string runTaskCommand (
std::vector <std::string>& args, std::vector <std::string>& args,
TDB& tdb, TDB& tdb,
Config& conf) Config& conf,
bool gc /* = false */)
{ {
// If argc == 1 and the default.command configuration variable is set, // If argc == 1 and the default.command configuration variable is set,
// then use that, otherwise stick with argc/argv. // then use that, otherwise stick with argc/argv.
@ -754,36 +767,40 @@ void runTaskCommand (
T task; T task;
parse (args, command, task, conf); parse (args, command, task, conf);
if (command == "add") handleAdd (tdb, task, conf); std::string out = "";
else if (command == "projects") handleProjects (tdb, task, conf);
else if (command == "tags") handleTags (tdb, task, conf); if (command == "" && task.getId ()) { handleModify (tdb, task, conf); }
else if (command == "list") handleList (tdb, task, conf); else if (command == "add") { handleAdd (tdb, task, conf); }
else if (command == "info") handleInfo (tdb, task, conf); else if (command == "done") { handleDone (tdb, task, conf); }
else if (command == "undelete") handleUndelete (tdb, task, conf); else if (command == "export") { handleExport (tdb, task, conf); }
else if (command == "long") handleLongList (tdb, task, conf); else if (command == "projects") { out = handleProjects (tdb, task, conf); }
else if (command == "ls") handleSmallList (tdb, task, conf); else if (command == "tags") { out = handleTags (tdb, task, conf); }
else if (command == "colors") handleColor ( conf); else if (command == "info") { out = handleInfo (tdb, task, conf); }
else if (command == "completed") handleCompleted (tdb, task, conf); else if (command == "undelete") { out = handleUndelete (tdb, task, conf); }
else if (command == "delete") handleDelete (tdb, task, conf); else if (command == "delete") { out = handleDelete (tdb, task, conf); }
else if (command == "start") handleStart (tdb, task, conf); else if (command == "start") { out = handleStart (tdb, task, conf); }
else if (command == "stop") handleStop (tdb, task, conf); else if (command == "stop") { out = handleStop (tdb, task, conf); }
else if (command == "done") handleDone (tdb, task, conf); else if (command == "undo") { out = handleUndo (tdb, task, conf); }
else if (command == "undo") handleUndo (tdb, task, conf); else if (command == "stats") { out = handleReportStats (tdb, task, conf); }
else if (command == "export") handleExport (tdb, task, conf); else if (command == "list") { if (gc) tdb.gc (); out = handleList (tdb, task, conf); }
else if (command == "version") handleVersion ( conf); else if (command == "long") { if (gc) tdb.gc (); out = handleLongList (tdb, task, conf); }
else if (command == "summary") handleReportSummary (tdb, task, conf); else if (command == "ls") { if (gc) tdb.gc (); out = handleSmallList (tdb, task, conf); }
else if (command == "next") handleReportNext (tdb, task, conf); else if (command == "completed") { if (gc) tdb.gc (); out = handleCompleted (tdb, task, conf); }
else if (command == "history") handleReportHistory (tdb, task, conf); else if (command == "summary") { if (gc) tdb.gc (); out = handleReportSummary (tdb, task, conf); }
else if (command == "ghistory") handleReportGHistory (tdb, task, conf); else if (command == "next") { if (gc) tdb.gc (); out = handleReportNext (tdb, task, conf); }
else if (command == "calendar") handleReportCalendar (tdb, task, conf); else if (command == "history") { if (gc) tdb.gc (); out = handleReportHistory (tdb, task, conf); }
else if (command == "active") handleReportActive (tdb, task, conf); else if (command == "ghistory") { if (gc) tdb.gc (); out = handleReportGHistory (tdb, task, conf); }
else if (command == "overdue") handleReportOverdue (tdb, task, conf); else if (command == "calendar") { if (gc) tdb.gc (); out = handleReportCalendar (tdb, task, conf); }
else if (command == "oldest") handleReportOldest (tdb, task, conf); else if (command == "active") { if (gc) tdb.gc (); out = handleReportActive (tdb, task, conf); }
else if (command == "newest") handleReportNewest (tdb, task, conf); else if (command == "overdue") { if (gc) tdb.gc (); out = handleReportOverdue (tdb, task, conf); }
else if (command == "stats") handleReportStats (tdb, task, conf); else if (command == "oldest") { if (gc) tdb.gc (); out = handleReportOldest (tdb, task, conf); }
else if (command == "" && task.getId ()) handleModify (tdb, task, conf); else if (command == "newest") { if (gc) tdb.gc (); out = handleReportNewest (tdb, task, conf); }
else if (command == "help") longUsage (conf); else if (command == "colors") { out = handleColor ( conf); }
else shortUsage (conf); else if (command == "version") { out = handleVersion ( conf); }
else if (command == "help") { longUsage ( conf); }
else { shortUsage ( conf); }
return out;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View file

@ -67,41 +67,41 @@ bool generateDueDates (T&, std::vector <Date>&);
Date getNextRecurrence (Date&, std::string&); Date getNextRecurrence (Date&, std::string&);
void updateRecurrenceMask (TDB&, std::vector <T>&, T&); void updateRecurrenceMask (TDB&, std::vector <T>&, T&);
void onChangeCallback (); void onChangeCallback ();
void runTaskCommand (int, char**, TDB&, Config&); std::string runTaskCommand (int, char**, TDB&, Config&, bool gc = true);
void runTaskCommand (std::vector <std::string>&, TDB&, Config&); std::string runTaskCommand (std::vector <std::string>&, TDB&, Config&, bool gc = false);
// command.cpp // command.cpp
void handleAdd (TDB&, T&, Config&); void handleAdd (TDB&, T&, Config&);
void handleProjects (TDB&, T&, Config&);
void handleTags (TDB&, T&, Config&);
void handleUndelete (TDB&, T&, Config&);
void handleVersion (Config&);
void handleExport (TDB&, T&, 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 handleDone (TDB&, T&, Config&);
void handleUndo (TDB&, T&, Config&);
void handleModify (TDB&, T&, Config&); void handleModify (TDB&, T&, Config&);
void handleColor (Config&); std::string handleProjects (TDB&, T&, Config&);
std::string handleTags (TDB&, T&, Config&);
std::string handleUndelete (TDB&, T&, Config&);
std::string handleVersion (Config&);
std::string handleDelete (TDB&, T&, Config&);
std::string handleStart (TDB&, T&, Config&);
std::string handleStop (TDB&, T&, Config&);
std::string handleUndo (TDB&, T&, Config&);
std::string handleColor (Config&);
// report.cpp // report.cpp
void filter (std::vector<T>&, T&); void filter (std::vector<T>&, T&);
void handleList (TDB&, T&, Config&); std::string handleList (TDB&, T&, Config&);
void handleInfo (TDB&, T&, Config&); std::string handleInfo (TDB&, T&, Config&);
void handleLongList (TDB&, T&, Config&); std::string handleLongList (TDB&, T&, Config&);
void handleSmallList (TDB&, T&, Config&); std::string handleSmallList (TDB&, T&, Config&);
void handleCompleted (TDB&, T&, Config&); std::string handleCompleted (TDB&, T&, Config&);
void handleReportSummary (TDB&, T&, Config&); std::string handleReportSummary (TDB&, T&, Config&);
void handleReportNext (TDB&, T&, Config&); std::string handleReportNext (TDB&, T&, Config&);
void handleReportHistory (TDB&, T&, Config&); std::string handleReportHistory (TDB&, T&, Config&);
void handleReportGHistory (TDB&, T&, Config&); std::string handleReportGHistory (TDB&, T&, Config&);
void handleReportCalendar (TDB&, T&, Config&); std::string handleReportCalendar (TDB&, T&, Config&);
void handleReportActive (TDB&, T&, Config&); std::string handleReportActive (TDB&, T&, Config&);
void handleReportOverdue (TDB&, T&, Config&); std::string handleReportOverdue (TDB&, T&, Config&);
void handleReportStats (TDB&, T&, Config&); std::string handleReportStats (TDB&, T&, Config&);
void handleReportOldest (TDB&, T&, Config&); std::string handleReportOldest (TDB&, T&, Config&);
void handleReportNewest (TDB&, T&, Config&); std::string handleReportNewest (TDB&, T&, Config&);
// util.cpp // util.cpp
bool confirm (const std::string&); bool confirm (const std::string&);

View file

@ -1,15 +0,0 @@
./task li due:monday
./task li due:tuesday
./task li due:wednesday
./task li due:thursday
./task li due:friday
./task li due:saturday
./task li due:sunday
./task li due:yesterday
./task li due:today
./task li due:tomorrow
./task li due:eow
./task li due:eom
./task li due:eoy
./task li due:21st