Compare commits

..

1 Commits

Author SHA1 Message Date
Federico Hernandez
462f27fce7 Changed epoch to be 12/22 for UTC 2009-08-18 14:34:17 +02:00
37 changed files with 200 additions and 758 deletions

1
.gitignore vendored
View File

@@ -15,4 +15,5 @@ www.xls
src/tests/all.log
src/tests/*.data
*~
movie*
.*.swp

View File

@@ -17,7 +17,6 @@ The following submitted code, packages or analysis, and deserve special thanks:
P.C. Shyamshankar
Johan Friis
Steven de Brouwer
Pietro Cerutti
Thanks to the following, who submitted detailed bug reports and excellent suggestions:
Eugene Kramer
@@ -35,7 +34,6 @@ Thanks to the following, who submitted detailed bug reports and excellent sugges
Eric Farris
Bruce Dillahunty
Askme Too
Mike Adonay
Thomas@BIC
Ian Mortimer

View File

@@ -1,42 +1,7 @@
------ current release ---------------------------
1.8.1 (8/20/2009)
+ Fixed bug #231 that broke the build on OpenBSD 32-bit due to a time_t
and int collision (thanks to Pietro Cerutti).
+ Fixed bug #241 that prevented bash's tab-completion of projects in Fedora
11 and likely anything using bash-4 (thanks to John Florian).
+ Fixed bug #242 that sometimes causes the ID echoed after a task is added
to be incorrect (thanks to John Florian).
+ Fixed bug #245 that quoted date fields on export, that were subsequently
improperly parsed on import (thanks to John Florian).
+ Fixed bug #248 where single and double quotes are both stored as
ampersand-quot-semi (thanks to John Florian).
+ Fixed bug #249 that caused annotations with the same date to be lost after
a "task edit" command (thanks to Federico Hernandez).
+ Fixed bug #250 whereby rc.dateformat was not observed when parsing the
creation date of an annotation (thanks to Federico Hernandez).
+ Fixed bug #251 whereby the presence of annotations cause the .hasnt attribute
modifier to not work (thanks to John Florian).
+ Fixed bug #252 that prevented use of attribute modifiers on dates to effect
a range, such as "task ls due.after:eom due.before:eoy" (thanks to John
Florian).
+ Fixed bug #256 that allowed a recurring task with no due date.
+ Fixed bug #257 where an extant ~/.taskrc file prevented the override and
automatic creation of an alternate rc file (thanks to Zach Frazier).
+ Fixed bug #259 that cause a build failure on Snow Leopard 10a432.
+ Fixed bug #260 whereby the start, stop and delete commands did not complain
when filter arguments were specified, even though they were ignored
(thanks to T. Charles Yun).
+ Fixed bug that allowed a recurring task to be added without a due date.
+ Fixed bug that displays the wrong .taskrc file name on override (thanks to
Federico Hernandez).
+ Fixed bug that failed to suppress color control code in the header and footnote
when redirecting output to a file (thanks to John Florian).
------ old releases ------------------------------
1.8.0 (7/21/2009) 14977ef317bd004dae2f2c313e806af9f2a2140c
1.8.0 (7/21/2009)
+ Added zsh tab completion script (thanks to P.C. Shyamshankar).
+ Fixed bug that cause the _forcecolor configuration variable to be
considered obsolete (thank to Bruce Dillahunty).
@@ -105,7 +70,9 @@
and completed tasks.
+ Now over 1,600 unit tests, helping to maintain code quality.
1.7.1 (6/8/2009) 1422a15cbc470cff590bf06daad20d01fe1b05ef
------ old releases ------------------------------
1.7.1 (6/8/2009)
+ Fixed build failure on OpenBSD (thanks to Mike Adonay).
+ Took the opportunity of a patch release to update the various email
addresses and URLs in the various documents.

2
NEWS
View File

@@ -1,5 +1,5 @@
New Features in task 1.8
New Features in task 1.8.0
- Attribute modifiers, for precise queries
- Improved calendar feature

View File

@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.61)
AC_INIT(task, 1.8.1, support@taskwarrior.org)
AC_INIT(task, 1.8.0, support@taskwarrior.org)
CFLAGS="${CFLAGS=}"
CXXFLAGS="${CXXFLAGS=}"

View File

@@ -1,4 +1,4 @@
.TH task-tutorial 5 2009-08-14 "task 1.8.1" "User Manuals"
.TH task-tutorial 5 2009-07-14 "Task 1.8.0" "User Manuals"
.SH NAME
task-tutorial \- A tutorial for the task(1) command line todo manager.

View File

@@ -1,4 +1,4 @@
.TH task 1 2009-08-14 "task 1.8.1" "User Manuals"
.TH task 1 2009-07-14 "Task 1.8.0" "User Manuals"
.SH NAME
task \- A command line todo manager.

View File

@@ -1,4 +1,4 @@
.TH taskrc 5 2009-08-14 "task 1.8.1" "User Manuals"
.TH taskrc 5 2009-07-14 "Task 1.8.0" "User Manuals"
.SH NAME
taskrc \- Configuration file for the task(1) command

View File

@@ -1,4 +1,4 @@
# setup.hint for task 1.8.1-1
# setup.hint for task 1.7.1-1
category: Utils
requires: libncurses9 cygwin
sdesc: A command-line to do list manager

View File

@@ -1,4 +1,4 @@
task 1.8.1-1
task 1.7.1-1
------------------------------------------
A command-line to do list manager that can be used
@@ -28,10 +28,10 @@ Language:
------------------------------------
Build instructions:
unpack task-1.8.1-1-src.tar.bz2
unpack task-1.7.1-1-src.tar.bz2
if you use setup to install this src package,
it will be unpacked under /usr/src automatically
cd /usr/src/task-1.8.1-1
cd /usr/src/task-1.7.1-1
./configure --prefix=/usr
make
make install
@@ -42,4 +42,4 @@ task was packaged for cygwin by
Federico Hernandez <ultrafredde@gmail.com> and
is licensed under the GPL
---- task-1.8.1-1 -- 2009-08-20 ----
---- task-1.7.1-1 -- 2009-06-17 ----

View File

@@ -1,8 +1,8 @@
diff -Nrup task-1.8.1-1/CYGWIN-PATCHES/setup.hint task-1.8.1-1.cygwin/CYGWIN-PATCHES/setup.hint
--- task-1.8.1-1/CYGWIN-PATCHES/setup.hint 1970-01-01 01:00:00.000000000 +0100
+++ task-1.8.1-1.cygwin/CYGWIN-PATCHES/setup.hint 2009-08-20 15:47:56.304750000 +0200
diff -Nrup task-1.7.1-1/CYGWIN-PATCHES/setup.hint task-1.7.1-1.cygwin/CYGWIN-PATCHES/setup.hint
--- task-1.7.1-1/CYGWIN-PATCHES/setup.hint 1970-01-01 01:00:00.000000000 +0100
+++ task-1.7.1-1.cygwin/CYGWIN-PATCHES/setup.hint 2009-06-17 15:47:56.304750000 +0200
@@ -0,0 +1,10 @@
+# setup.hint for task 1.8.1-1
+# setup.hint for task 1.7.1-1
+category: Utils
+requires: libncurses9 cygwin
+sdesc: A command-line to do list manager
@@ -12,11 +12,11 @@ diff -Nrup task-1.8.1-1/CYGWIN-PATCHES/setup.hint task-1.8.1-1.cygwin/CYGWIN-PAT
+reports and graphs, lots of manipulation commands,
+low-level API, abbreviations for all commands and
+options, multiuser file locking, recurring tasks."
diff -Nrup task-1.8.1-1/CYGWIN-PATCHES/task-1.8.1-1.README task-1.8.1-1.cygwin/CYGWIN-PATCHES/task-1.8.1-1.README
--- task-1.8.1-1/CYGWIN-PATCHES/task-1.8.1-1.README 1970-01-01 01:00:00.000000000 +0100
+++ task-1.8.1-1.cygwin/CYGWIN-PATCHES/task-1.8.1-1.README 2009-08-20 15:47:44.320375000 +0200
diff -Nrup task-1.7.1-1/CYGWIN-PATCHES/task-1.7.1-1.README task-1.7.1-1.cygwin/CYGWIN-PATCHES/task-1.7.1-1.README
--- task-1.7.1-1/CYGWIN-PATCHES/task-1.7.1-1.README 1970-01-01 01:00:00.000000000 +0100
+++ task-1.7.1-1.cygwin/CYGWIN-PATCHES/task-1.7.1-1.README 2009-06-17 15:47:44.320375000 +0200
@@ -0,0 +1,45 @@
+task 1.8.1-1
+task 1.7.1-1
+------------------------------------------
+
+A command-line to do list manager that can be used
@@ -46,10 +46,10 @@ diff -Nrup task-1.8.1-1/CYGWIN-PATCHES/task-1.8.1-1.README task-1.8.1-1.cygwin/C
+------------------------------------
+
+Build instructions:
+ unpack task-1.8.1-1-src.tar.bz2
+ unpack task-1.7.1-1-src.tar.bz2
+ if you use setup to install this src package,
+ it will be unpacked under /usr/src automatically
+ cd /usr/src/task-1.8.1-1
+ cd /usr/src/task-1.7.1-1
+ ./configure --prefix=/usr
+ make
+ make install
@@ -60,4 +60,4 @@ diff -Nrup task-1.8.1-1/CYGWIN-PATCHES/task-1.8.1-1.README task-1.8.1-1.cygwin/C
+Federico Hernandez <ultrafredde@gmail.com> and
+is licensed under the GPL
+
+---- task-1.8.1-1 -- 2009-08-20 ----
+---- task-1.7.1-1 -- 2009-06-17 ----

View File

@@ -1,4 +1,4 @@
task 1.8.1-1
task 1.7.1-1
------------------------------------------
A command-line to do list manager that can be used
@@ -28,10 +28,10 @@ Language:
------------------------------------
Build instructions:
unpack task-1.8.1-1-src.tar.bz2
unpack task-1.7.1-1-src.tar.bz2
if you use setup to install this src package,
it will be unpacked under /usr/src automatically
cd /usr/src/task-1.8.1-1
cd /usr/src/task-1.7.1-1
./configure --prefix=/usr
make
make install
@@ -42,4 +42,4 @@ task was packaged for cygwin by
Federico Hernandez <ultrafredde@gmail.com> and
is licensed under the GPL
---- task-1.8.1-1 -- 2009-08-20 ----
---- task-1.7.1-1 -- 2009-06-17 ----

View File

@@ -1,6 +1,6 @@
Name: task
Version: 1.8.1
Release: 1%{?dist}
Version: 1.8.0
Release: 0%{?dist}
Summary: A command-line to do list manager
Group: Applications/Productivity
@@ -40,25 +40,18 @@ rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root,-)
%doc AUTHORS ChangeLog COPYING NEWS README scripts i18n
%doc AUTHORS ChangeLog COPYING NEWS README scripts
%{_bindir}/task
%{_mandir}/man1/task.1.gz
%{_mandir}/man5/taskrc.5.gz
%{_mandir}/man5/task-tutorial.5.gz
%config(noreplace) %{_sysconfdir}/bash_completion.d
%{_sysconfdir}/bash_completion.d
%changelog
* Thu Aug 20 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.8.1-1
Intial RPM for task bugfix release 1.8.1
* Tue Jul 21 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.8.0-1
* Mon Jun 15 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.8.0-0
Intial RPM for task release 1.8.0
* Mon Jul 13 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.8.0.beta3-1
Intial RPM for task beta release 1.8.0.beta3
* Wed Jul 08 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.8.0.beta2-1
Intial RPM for task beta release 1.8.0.beta2
* Tue Jul 07 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.8.0.beta1-1
Intial RPM for task beta release 1.8.0.beta1
Installs now bash_completion file
* Tue Jun 08 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.7.1-2
- Fixed inclusion of manpages.
* Tue Jun 08 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.7.1-1

View File

@@ -1,32 +1,8 @@
task (1.8.1-0ubuntu1) jaunty; urgency=low
* Initial deb package for task bugfix release 1.8.1
-- Federico Hernandez <ultrafredde@gmail.com> Thu, 20 Aug 2009 20:26:33 +0200
task (1.8.0-0ubuntu1) jaunty; urgency=low
* Initial deb package for task release 1.8.0
-- Federico Hernandez <ultrafredde@gmail.com> Tue, 21 Jul 2009 15:26:33 +0200
task (1.8.0-0ubuntu1~beta3) jaunty; urgency=low
* Initial deb package for task beta release 1.8.0.beta3
-- Federico Hernandez <ultrafredde@gmail.com> Mon, 13 Jul 2009 15:09:38 +0200
task (1.8.0-0ubuntu1~beta2) jaunty; urgency=low
* Initial deb package for task beta release 1.8.0.beta2
-- Federico Hernandez <ultrafredde@gmail.com> Wed, 08 Jul 2009 15:40:50 +0200
task (1.8.0-0ubuntu1~beta1) jaunty; urgency=low
* Initial deb package for task beta release 1.8.0.beta1
-- Federico Hernandez <ultrafredde@gmail.com> Tue, 07 Jul 2009 01:35:28 +0200
-- Federico Hernandez <ultrafredde@gmail.com> Thu, 11 Jun 2009 23:02:28 +0200
task (1.7.1-0ubuntu1) jaunty; urgency=low

View File

@@ -1,6 +1,6 @@
This package was debianized by:
Federico Hernandez <ultrafredde@gmail.com> on Thu, 20 Aug 2009 20:26:33 +0200
Federico Hernandez <ultrafredde@gmail.com> on Thu, 11 Jun 2009 23:02:28 +0200
It was downloaded from:
@@ -9,9 +9,6 @@ It was downloaded from:
Upstream Authors:
Paul Beckingham <paul@beckingham.net>
Federico Hernandez
David J Patrick
John Florian
Damian Glenny
Andy Lester
H. İbrahim Güngör
@@ -20,18 +17,18 @@ Upstream Authors:
Benjamin Tegarden
Chris Pride
Richard Querin
Federico Hernandez
T. Charles Yun
David J Patrick
P.C. Shyamshankar
Johan Friis
Steven de Brouwer
Pietro Cerutti
Copyright:
Copyright 2006 - 2009, Paul Beckingham
Copyright 2009 Federico Hernandez
Copyright 2009 P.C. Shyamshankar
Copyright 2009 John Florian
License:

View File

@@ -1,2 +0,0 @@
scripts
i18n

View File

@@ -31,9 +31,8 @@ binary-arch: install
dh_installchangelogs
dh_installdocs
dh_installman
dh_installexamples
install -D -m644 scripts/bash/task_completion.sh $(CURDIR)/debian/task/etc/bash_completion.d/task
rm -rf $(CURDIR)/debian/task/usr/share/doc/task-1.8.1
install -D -m644 task_completion.sh $(CURDIR)/debian/task/etc/bash_completion.d/task
rm -rf $(CURDIR)/debian/task/usr/share/doc/task-1.7.1
dh_strip
dh_compress
dh_fixperms

View File

@@ -48,6 +48,10 @@
# http://taskwarrior.org
#
_task_get_projects() {
task _projects
}
_task_get_tags() {
task _tags
}
@@ -56,10 +60,6 @@ _task_get_config() {
task _config
}
_task_offer_projects() {
COMPREPLY=( $(compgen -W "$(task _projects)" -- ${cur/*:/}) )
}
_task()
{
local cur prev opts base
@@ -67,61 +67,34 @@ _task()
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
if [ ${#COMP_WORDS[*]} -gt 2 ]
then
prev2="${COMP_WORDS[COMP_CWORD-2]}"
else
prev2=""
fi
# echo -e "\ncur='$cur'"
# echo "prev='$prev'"
# echo "prev2='$prev2'"
opts="$(task _commands) $(task _ids)"
case "${prev}" in
:)
case "${prev2}" in
pro*)
_task_offer_projects
return 0
;;
esac
case "${cur}" in
pro*:*)
local projects=$(_task_get_projects)
local partial_project="${cur/*:/}"
COMPREPLY=( $(compgen -W "${projects}" -- ${partial_project}) )
return 0
;;
*)
case "${cur}" in
pro*:*)
_task_offer_projects
return 0
;;
:)
case "${prev}" in
pro*)
_task_offer_projects
return 0
;;
esac
;;
+*)
local tags=$(_task_get_tags | sed 's/^/+/')
COMPREPLY=( $(compgen -W "${tags}" -- ${cur}) )
return 0
;;
-*)
local tags=$(_task_get_tags | sed 's/^/-/')
COMPREPLY=( $(compgen -W "${tags}" -- ${cur}) )
return 0
;;
rc.*)
local config=$(_task_get_config | sed -e 's/^/rc\./' -e 's/$/:/')
COMPREPLY=( $(compgen -W "${config}" -- ${cur}) )
return 0
;;
esac
+*)
local tags=$(_task_get_tags | sed 's/^/+/')
COMPREPLY=( $(compgen -W "${tags}" -- ${cur}) )
return 0
;;
-*)
local tags=$(_task_get_tags | sed 's/^/-/')
COMPREPLY=( $(compgen -W "${tags}" -- ${cur}) )
return 0
;;
rc.*)
local config=$(_task_get_config | sed 's/^/rc\./')
COMPREPLY=( $(compgen -W "${config}" -- ${cur}) )
return 0
;;
esac
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
}
complete -o nospace -F _task task
complete -F _task task

View File

@@ -407,17 +407,6 @@ std::string Att::type (const std::string& name) const
return "text";
}
////////////////////////////////////////////////////////////////////////////////
// The type of an attribute is useful for modifier evaluation.
std::string Att::modType (const std::string& name) const
{
if (name == "hasnt" ||
name == "isnt")
return "negative";
return "positive";
}
////////////////////////////////////////////////////////////////////////////////
//
// start --> name --> . --> mod --> : --> " --> value --> " --> end
@@ -472,7 +461,7 @@ void Att::parse (Nibbler& n)
else
throw std::string ("Missing : after attribute name"); // TODO i18n
/* TODO This might be too slow to include. Test this assumption.
/* TODO This might be too slow to include. Test.
validNameValue (mName, mMod, mValue);
*/
}
@@ -722,11 +711,8 @@ void Att::encode (std::string& value) const
while ((i = value.find ('\t')) != std::string::npos)
value.replace (i, 1, "&tab;"); // no i18n
while ((i = value.find ('\'')) != std::string::npos)
value.replace (i, 1, "&squot;"); // no i18n
while ((i = value.find ('"')) != std::string::npos)
value.replace (i, 1, "&dquot;"); // no i18n
value.replace (i, 1, "&quot;"); // no i18n
while ((i = value.find (',')) != std::string::npos)
value.replace (i, 1, "&comma;"); // no i18n
@@ -744,8 +730,7 @@ void Att::encode (std::string& value) const
////////////////////////////////////////////////////////////////////////////////
// Decode values after parse.
// \t <- &tab;
// " <- &quot; or &dquot;
// ' <- &squot;
// " <- &quot;
// , <- &comma;
// [ <- &open;
// ] <- &close;
@@ -757,12 +742,6 @@ void Att::decode (std::string& value) const
while ((i = value.find ("&tab;")) != std::string::npos) // no i18n
value.replace (i, 5, "\t");
while ((i = value.find ("&dquot;")) != std::string::npos) // no i18n
value.replace (i, 7, "\"");
while ((i = value.find ("&squot;")) != std::string::npos) // no i18n
value.replace (i, 7, "'");
while ((i = value.find ("&quot;")) != std::string::npos) // no i18n
value.replace (i, 6, "\"");

View File

@@ -50,7 +50,6 @@ public:
static bool validNameValue (std::string&, std::string&, std::string&);
static bool validMod (const std::string&);
std::string type (const std::string&) const;
std::string modType (const std::string&) const;
void parse (const std::string&);
void parse (Nibbler&);
bool match (const Att&) const;

View File

@@ -148,27 +148,18 @@ int Context::run ()
// Dump all debug messages.
if (config.get (std::string ("debug"), false))
foreach (d, debugMessages)
if (config.get ("color", true) || config.get (std::string ("_forcecolor"), false))
std::cout << colorizeDebug (*d) << std::endl;
else
std::cout << *d << std::endl;
std::cout << colorizeDebug (*d) << std::endl;
// Dump all headers.
foreach (h, headers)
if (config.get ("color", true) || config.get (std::string ("_forcecolor"), false))
std::cout << colorizeHeader (*h) << std::endl;
else
std::cout << *h << std::endl;
std::cout << colorizeHeader (*h) << std::endl;
// Dump the report output.
std::cout << output;
// Dump all footnotes.
foreach (f, footnotes)
if (config.get ("color", true) || config.get (std::string ("_forcecolor"), false))
std::cout << colorizeFootnote (*f) << std::endl;
else
std::cout << *f << std::endl;
std::cout << colorizeFootnote (*f) << std::endl;
return 0;
}
@@ -316,18 +307,6 @@ std::string Context::canonicalize (const std::string& input) const
return canonical;
}
////////////////////////////////////////////////////////////////////////////////
void Context::disallowModification () const
{
if (task.size () ||
subst.mFrom != "" ||
tagAdditions.size () ||
tagRemovals.size ())
throw std::string ("The '")
+ cmd.command
+ "' command does not allow further modification of a task.";
}
////////////////////////////////////////////////////////////////////////////////
void Context::loadCorrectConfigFile ()
{
@@ -351,14 +330,6 @@ void Context::loadCorrectConfigFile ()
else if (arg->substr (0, 3) == "rc:")
{
rc = arg->substr (3, std::string::npos);
home = rc;
std::string::size_type last_slash = rc.rfind ("/");
if (last_slash != std::string::npos)
home = rc.substr (0, last_slash);
else
home = ".";
args.erase (arg);
header ("Using alternate .taskrc file " + rc); // TODO i18n
break;
@@ -387,19 +358,13 @@ void Context::loadCorrectConfigFile ()
}
// Do we need to create a default rc?
if (access (rc.c_str (), F_OK))
if (access (rc.c_str (), F_OK) &&
confirm ("A configuration file could not be found in " // TODO i18n
+ home
+ "\n\n"
+ "Would you like a sample .taskrc created, so task can proceed?"))
{
if (confirm ("A configuration file could not be found in " // TODO i18n
+ home
+ "\n\n"
+ "Would you like a sample "
+ rc
+ " created, so task can proceed?"))
{
config.createDefaultRC (rc, data);
}
else
throw std::string ("Cannot proceed without rc file.");
config.createDefaultRC (rc, data);
}
// Create data location, if necessary.
@@ -563,12 +528,7 @@ void Context::parse (
attribute.mod (mod);
attribute.value (value);
// Preserve modifier in the key, to allow multiple modifiers on the
// same attribute. Bug #252.
if (name != "" && mod != "")
parseTask[name + "." + mod] = attribute;
else
parseTask[name] = attribute;
parseTask[attribute.name ()] = attribute;
}
// *arg has the appearance of an attribute (foo:bar), but isn't
@@ -697,46 +657,46 @@ void Context::autoFilter (Task& t, Filter& f)
foreach (att, t)
{
// Words are found in the description using the .has modifier.
if (att->second.name () == "description" && att->second.mod () == "")
if (att->first == "description" && att->second.mod () == "")
{
std::vector <std::string> words;
split (words, att->second.value (), ' ');
foreach (word, words)
{
f.push_back (Att ("description", "has", *word));
debug ("auto filter: " + att->second.name () + ".has:" + *word);
debug ("auto filter: " + att->first + ".has:" + *word);
}
}
// Projects are matched left-most.
else if (att->second.name () == "project" && att->second.mod () == "")
else if (att->first == "project" && att->second.mod () == "")
{
if (att->second.value () != "")
{
f.push_back (Att ("project", "startswith", att->second.value ()));
debug ("auto filter: " + att->second.name () + ".startswith:" + att->second.value ());
debug ("auto filter: " + att->first + ".startswith:" + att->second.value ());
}
else
{
f.push_back (Att ("project", "is", att->second.value ()));
debug ("auto filter: " + att->second.name () + ".is:" + att->second.value ());
debug ("auto filter: " + att->first + ".is:" + att->second.value ());
}
}
// The limit attribute does not participate in filtering, and needs to be
// specifically handled in handleCustomReport.
else if (att->second.name () == "limit")
else if (att->first == "limit")
{
}
// Every task has a unique uuid by default, and it shouldn't be included,
// because it is guaranteed to not match.
else if (att->second.name () == "uuid")
else if (att->first == "uuid")
{
}
// The mechanism for filtering on tags is +/-<tag>.
else if (att->second.name () == "tags")
else if (att->first == "tags")
{
}
@@ -745,7 +705,7 @@ void Context::autoFilter (Task& t, Filter& f)
{
f.push_back (att->second);
debug ("auto filter: " +
att->second.name () +
att->first +
(att->second.mod () != "" ?
("." + att->second.mod () + ":") :
":") +

View File

@@ -65,7 +65,6 @@ public:
void clear ();
std::string canonicalize (const std::string&) const;
void disallowModification () const;
private:
void loadCorrectConfigFile ();

View File

@@ -51,6 +51,12 @@ Duration::Duration (const std::string& input)
parse (input);
}
////////////////////////////////////////////////////////////////////////////////
Duration::operator int ()
{
return (int) mDays;
}
////////////////////////////////////////////////////////////////////////////////
Duration::operator time_t ()
{

View File

@@ -40,6 +40,7 @@ public:
bool operator> (const Duration&);
~Duration (); // Destructor
operator int ();
operator time_t ();
operator std::string ();

View File

@@ -40,51 +40,37 @@ bool Filter::pass (const Record& record) const
// First do description/annotation matches.
foreach (att, (*this))
{
// Descriptions have special handling such that they are linked to
// annotations, and filtering on description implies identical filtering
// on annotations, and that both filter matches must succeed for the filter
// to succeed overall.
// Descriptions have special handling.
if (att->name () == "description")
{
bool description_result = true;
int annotation_pass_count = 0;
int annotation_fail_count = 0;
if ((r = record.find (att->name ())) != record.end ())
{
description_result = att->match (r->second);
foreach (ra, record)
// A description match failure can be salvaged by an annotation match.
if (! att->match (r->second))
{
if (ra->first.length () > 11 &&
ra->first.substr (0, 11) == "annotation_")
bool annoMatch = false;
foreach (ra, record)
{
if (att->match (ra->second))
++annotation_pass_count;
else
++annotation_fail_count;
if (ra->first.length () > 11 &&
ra->first.substr (0, 11) == "annotation_")
{
if (att->match (ra->second))
{
annoMatch = true;
break;
}
}
}
if (!annoMatch)
return false;
}
}
else if (! att->match (Att ()))
return false;
// This innocuous little if-else took significantly more thinking and
// debugging than anything else in task. Only change this code if you
// are willing to invest a week understanding and testing it.
if (att->modType (att->mod ()) == "positive")
{
if (! (description_result || annotation_pass_count > 0))
return false;
}
else
{
if (!description_result || annotation_fail_count > 0)
return false;
}
}
// Annotations are skipped, because they are handled above.
// Annotations are skipped.
else if (att->name ().length () > 11 &&
att->name ().substr (0, 11) == "annotation_")
{

View File

@@ -67,8 +67,8 @@ bool Task::operator== (const Task& other)
return false;
foreach (att, *this)
if (att->second.name () != "uuid")
if (att->second.value () != other.get (att->second.name ()))
if (att->first != "uuid")
if (att->second.value () != other.get (att->first))
return false;
return true;
@@ -363,12 +363,12 @@ std::string Task::composeCSV () const
out << get ("start") << ","; // No i18n
if (has ("due"))
out << get ("due") << ","; // No i18n
out << "'" << get ("due") << "',"; // No i18n
else
out << ","; // No i18n
if (has ("recur"))
out << get ("recur") << ","; // No i18n
out << "'" << get ("recur") << "',"; // No i18n
else
out << ","; // No i18n

View File

@@ -84,15 +84,6 @@ std::string handleAdd ()
foreach (tag, context.tagAdditions)
context.task.addTag (*tag);
// Perform some logical consistency checks.
if (context.task.has ("recur") &&
!context.task.has ("due"))
throw std::string ("You cannot specify a recurring task without a due date.");
if (context.task.has ("until") &&
!context.task.has ("recur"))
throw std::string ("You cannot specify an until date for a non-recurring task.");
// Only valid tasks can be added.
context.task.validate ();
@@ -122,6 +113,7 @@ std::string handleProjects ()
std::vector <Task> tasks;
context.tdb.lock (context.config.get ("locking", true));
handleRecurrence ();
int quantity = context.tdb.loadPending (tasks, context.filter);
context.tdb.commit ();
context.tdb.unlock ();
@@ -207,6 +199,7 @@ std::string handleCompletionProjects ()
{
std::vector <Task> tasks;
context.tdb.lock (context.config.get ("locking", true));
handleRecurrence ();
Filter filter;
if (context.config.get (std::string ("complete.all.projects"), false))
@@ -240,6 +233,7 @@ std::string handleTags ()
std::vector <Task> tasks;
context.tdb.lock (context.config.get ("locking", true));
handleRecurrence ();
int quantity = context.tdb.loadPending (tasks, context.filter);
context.tdb.commit ();
context.tdb.unlock ();
@@ -302,6 +296,7 @@ std::string handleCompletionTags ()
{
std::vector <Task> tasks;
context.tdb.lock (context.config.get ("locking", true));
handleRecurrence ();
Filter filter;
if (context.config.get (std::string ("complete.all.tags"), false))
@@ -364,6 +359,7 @@ std::string handleCompletionIDs ()
{
std::vector <Task> tasks;
context.tdb.lock (context.config.get ("locking", true));
handleRecurrence ();
Filter filter;
context.tdb.loadPending (tasks, filter);
context.tdb.commit ();
@@ -387,8 +383,6 @@ std::string handleCompletionIDs ()
////////////////////////////////////////////////////////////////////////////////
void handleUndo ()
{
context.disallowModification ();
context.tdb.lock (context.config.get ("locking", true));
context.tdb.undo ();
context.tdb.unlock ();
@@ -559,10 +553,9 @@ std::string handleDelete ()
{
std::stringstream out;
context.disallowModification ();
std::vector <Task> tasks;
context.tdb.lock (context.config.get ("locking", true));
handleRecurrence ();
Filter filter;
context.tdb.loadPending (tasks, filter);
@@ -660,10 +653,9 @@ std::string handleStart ()
{
std::stringstream out;
context.disallowModification ();
std::vector <Task> tasks;
context.tdb.lock (context.config.get ("locking", true));
handleRecurrence ();
Filter filter;
context.tdb.loadPending (tasks, filter);
@@ -713,10 +705,9 @@ std::string handleStop ()
{
std::stringstream out;
context.disallowModification ();
std::vector <Task> tasks;
context.tdb.lock (context.config.get ("locking", true));
handleRecurrence ();
Filter filter;
context.tdb.loadPending (tasks, filter);
@@ -763,6 +754,7 @@ std::string handleDone ()
std::vector <Task> tasks;
context.tdb.lock (context.config.get ("locking", true));
handleRecurrence ();
Filter filter;
context.tdb.loadPending (tasks, filter);
@@ -893,6 +885,7 @@ std::string handleModify ()
std::vector <Task> tasks;
context.tdb.lock (context.config.get ("locking", true));
handleRecurrence ();
Filter filter;
context.tdb.loadPending (tasks, filter);
@@ -970,6 +963,7 @@ std::string handleAppend ()
std::vector <Task> tasks;
context.tdb.lock (context.config.get ("locking", true));
handleRecurrence ();
Filter filter;
context.tdb.loadPending (tasks, filter);
@@ -1365,12 +1359,12 @@ int deltaAttributes (Task& task)
foreach (att, context.task)
{
if (att->second.name () != "uuid" &&
att->second.name () != "description" &&
att->second.name () != "tags")
if (att->first != "uuid" &&
att->first != "description" &&
att->first != "tags")
{
// Modifying "wait" changes status.
if (att->second.name () == "wait")
if (att->first == "wait")
{
if (att->second.value () == "")
task.setStatus (Task::pending);
@@ -1379,9 +1373,8 @@ int deltaAttributes (Task& task)
}
if (att->second.value () == "")
task.remove (att->second.name ());
task.remove (att->first);
else
// One of the few places where the compound attribute name is used.
task.set (att->first, att->second.value ());
++changes;

View File

@@ -499,13 +499,7 @@ static void parseTask (Task& task, const std::string& after)
std::string::size_type gap = value.find (" ");
if (gap != std::string::npos)
{
Date when (value.substr (0, gap), context.config.get ("dateformat", "m/d/Y"));
// This guarantees that if more than one annotation has the same date,
// that the seconds will be different, thus unique, thus not squashed.
// Bug #249
when += (const int) annotations.size ();
Date when (value.substr (0, gap));
std::stringstream name;
name << "annotation_" << when.toEpoch ();
std::string text = trim (value.substr (gap, std::string::npos), "\t ");

View File

@@ -34,7 +34,7 @@
#include "Context.h"
//#include "text.h"
//#include "util.h"
#include "main.h"
//#include "main.h"
#include "i18n.h"
#include "../auto.h"

View File

@@ -1,83 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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_TASK
#define INCLUDED_TASK
#include <string>
#include "Record.h"
#include "Subst.h"
#include "Sequence.h"
class Task : public Record
{
public:
Task (); // Default constructor
Task (const Task&); // Copy constructor
Task& operator= (const Task&); // Assignment operator
bool operator== (const Task&); // Comparison operator
Task (const std::string&); // Parse
~Task (); // Destructor
void parse (const std::string&);
std::string composeCSV () const;
// Status values.
enum status {pending, completed, deleted, recurring, waiting};
// Public data.
int id;
// Series of helper functions.
static status textToStatus (const std::string&);
static std::string statusToText (status);
void setEntry ();
status getStatus ();
void setStatus (status);
int getTagCount ();
bool hasTag (const std::string&);
void addTag (const std::string&);
void addTags (const std::vector <std::string>&);
void getTags (std::vector<std::string>&) const;
void removeTag (const std::string&);
void getAnnotations (std::vector <Att>&) const;
void setAnnotations (const std::vector <Att>&);
void addAnnotation (const std::string&);
void removeAnnotations ();
void validate () const;
private:
int determineVersion (const std::string&);
void legacyParse (const std::string&);
};
#endif
////////////////////////////////////////////////////////////////////////////////

View File

@@ -75,9 +75,9 @@ int main (int argc, char** argv)
Att a5 ("name", "value");
t.is (a5.composeF4 (), "name:\"value\"", "Att::composeF4 simple");
a5.value ("\"");
t.is (a5.composeF4 (), "name:\"&dquot;\"", "Att::composeF4 encoded \"");
t.is (a5.composeF4 (), "name:\"&quot;\"", "Att::composeF4 encoded \"");
a5.value ("\t\",[]:");
t.is (a5.composeF4 (), "name:\"&tab;&dquot;&comma;&open;&close;&colon;\"", "Att::composeF4 fully encoded \\t\",[]:");
t.is (a5.composeF4 (), "name:\"&tab;&quot;&comma;&open;&close;&colon;\"", "Att::composeF4 fully encoded \\t\",[]:");
Att a6 ("name", 6);
t.is (a6.value_int (), 6, "Att::value_int get");
@@ -174,12 +174,12 @@ int main (int argc, char** argv)
n = Nibbler ("name:\"&quot;\"");
a7.parse (n);
t.is (a7.composeF4 (), "name:\"&dquot;\"",
t.is (a7.composeF4 (), "name:\"&quot;\"",
"Att::parse (name:\"&quot;\")");
n = Nibbler ("name:\"&tab;&quot;&comma;&open;&close;&colon;\"");
a7.parse (n);
t.is (a7.composeF4 (), "name:\"&tab;&dquot;&comma;&open;&close;&colon;\"",
t.is (a7.composeF4 (), "name:\"&tab;&quot;&comma;&open;&close;&colon;\"",
"Att::parse (name:\"&tab;&quot;&comma;&open;&close;&colon;\")");
n = Nibbler ("total gibberish");
@@ -216,19 +216,19 @@ int main (int argc, char** argv)
good = true;
try {a7.parse (n);} catch (...) {good = false;}
t.ok (good, "Att::parse (name:\"value)");
t.is (a7.composeF4 (), "name:\"&dquot;value\"", "Att::composeF4 -> name:\"&dquot;value\"");
t.is (a7.composeF4 (), "name:\"&quot;value\"", "Att::composeF4 -> name:\"&quot;value\"");
n = Nibbler ("name:value\"");
good = true;
try {a7.parse (n);} catch (...) {good = false;}
t.ok (good, "Att::parse (name:value\")");
t.is (a7.composeF4 (), "name:\"value&dquot;\"", "Att::composeF4 -> name:\"value&dquot;\"");
t.is (a7.composeF4 (), "name:\"value&quot;\"", "Att::composeF4 -> name:\"value&quot;\"");
n = Nibbler ("name:val\"ue");
good = true;
try {a7.parse (n);} catch (...) {good = false;}
t.ok (good, "Att::parse (name:val\"ue)");
t.is (a7.composeF4 (), "name:\"val&dquot;ue\"", "Att::composeF4 -> name:\"val&dquot;ue\"");
t.is (a7.composeF4 (), "name:\"val&quot;ue\"", "Att::composeF4 -> name:\"val&quot;ue\"");
n = Nibbler ("name\"");
good = true;

View File

@@ -1,106 +0,0 @@
#! /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 => 19;
# Create the rc file.
if (open my $fh, '>', 'hasnt.rc')
{
print $fh "data.location=.\n",
"confirmation=no\n";
close $fh;
ok (-r 'hasnt.rc', 'Created hasnt.rc');
}
# 1
qx{../task rc:hasnt.rc add foo};
# 2
qx{../task rc:hasnt.rc add foo};
qx{../task rc:hasnt.rc 2 annotate bar};
# 3
qx{../task rc:hasnt.rc add foo};
qx{../task rc:hasnt.rc 3 annotate bar};
sleep 2;
qx{../task rc:hasnt.rc 3 annotate baz};
# 4
qx{../task rc:hasnt.rc add bar};
# 5
qx{../task rc:hasnt.rc add bar};
qx{../task rc:hasnt.rc 5 annotate foo};
# 6
qx{../task rc:hasnt.rc add bar};
qx{../task rc:hasnt.rc 6 annotate foo};
sleep 2;
qx{../task rc:hasnt.rc 6 annotate baz};
#7
qx{../task rc:hasnt.rc add one};
qx{../task rc:hasnt.rc 7 annotate two};
sleep 2;
qx{../task rc:hasnt.rc 7 annotate three};
my $output = qx{../task rc:hasnt.rc ls description.has:foo};
like ($output, qr/\n 1/, '1 has foo -> yes');
like ($output, qr/\n 2/, '2 has foo -> yes');
like ($output, qr/\n 3/, '3 has foo -> yes');
unlike ($output, qr/\n 4/, '4 has foo -> no');
like ($output, qr/\n 5/, '5 has foo -> yes');
like ($output, qr/\n 6/, '6 has foo -> yes');
unlike ($output, qr/\n 7/, '7 has foo -> no');
$output = qx{../task rc:hasnt.rc ls description.hasnt:foo};
unlike ($output, qr/\n 1/, '1 hasnt foo -> no');
unlike ($output, qr/\n 2/, '2 hasnt foo -> no');
unlike ($output, qr/\n 3/, '3 hasnt foo -> no');
like ($output, qr/\n 4/, '4 hasnt foo -> yes');
unlike ($output, qr/\n 5/, '5 hasnt foo -> no');
unlike ($output, qr/\n 6/, '6 hasnt foo -> no');
like ($output, qr/\n 7/, '7 hasnt foo -> yes');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'completed.data';
ok (!-r 'completed.data', 'Removed completed.data');
unlink 'undo.data';
ok (!-r 'undo.data', 'Removed undo.data');
unlink 'hasnt.rc';
ok (!-r 'hasnt.rc', 'Removed hasnt.rc');
exit 0;

View File

@@ -1,65 +0,0 @@
#! /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 => 8;
# Create the rc file.
if (open my $fh, '>', 'range.rc')
{
print $fh "data.location=.\n",
"confirmation=no\n";
close $fh;
ok (-r 'range.rc', 'Created range.rc');
}
# Add three tasks, and attempt to list the middle one within a range.
qx{../task rc:range.rc add one due:8/1/2009};
qx{../task rc:range.rc add two due:8/3/2009};
qx{../task rc:range.rc add three due:8/5/2009};
my $output = qx{../task rc:range.rc ls due.after:8/2/2009 due.before:8/4/2009};
unlike ($output, qr/one/, 'Missing prior to range');
like ($output, qr/two/, 'Found within range');
unlike ($output, qr/three/, 'Missing after range');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'completed.data';
ok (!-r 'completed.data', 'Removed completed.data');
unlink 'undo.data';
ok (!-r 'undo.data', 'Removed undo.data');
unlink 'range.rc';
ok (!-r 'range.rc', 'Removed range.rc');
exit 0;

View File

@@ -1,61 +0,0 @@
#! /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",
"confirmation=no\n";
close $fh;
ok (-r 'recur.rc', 'Created recur.rc');
}
# Add a recurring task with no due date, look for expected error.
qx{../task rc:recur.rc add foo recur:daily};
my $output = qx{../task rc:recur.rc info 1};
unlike ($output, qr/Description\s+foo/, 'task not created - missing due date');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'completed.data';
ok (!-r 'completed.data', 'Removed completed.data');
unlink 'undo.data';
ok (!-r 'undo.data', 'Removed undo.data');
unlink 'recur.rc';
ok (!-r 'recur.rc', 'Removed recur.rc');
exit 0;

View File

@@ -1,62 +0,0 @@
#! /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, '>', 'extra.rc')
{
print $fh "data.location=.\n",
"confirmation=no\n";
close $fh;
ok (-r 'extra.rc', 'Created extra.rc');
}
qx{../task rc:extra.rc add foo};
my $output = qx{../task rc:extra.rc 1 start pri:L};
like ($output, qr/The 'start' command does not allow further modification of a task\./, 'no modifications allowed for start');
$output = qx{../task rc:extra.rc 1 stop pro:bar};
like ($output, qr/The 'stop' command does not allow further modification of a task\./, 'no modifications allowed for stop');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'completed.data';
ok (!-r 'completed.data', 'Removed completed.data');
unlink 'undo.data';
ok (!-r 'undo.data', 'Removed undo.data');
unlink 'extra.rc';
ok (!-r 'extra.rc', 'Removed extra.rc');
exit 0;

View File

@@ -42,7 +42,7 @@ if (open my $fh, '>', 'custom.rc')
ok (-r 'custom.rc', 'Created custom.rc');
}
# Add a recurring and non-recurring task, look for the indicator.
# Generate the usage screen, and locate the custom report on it.
qx{../task rc:custom.rc add foo due:tomorrow recur:weekly};
qx{../task rc:custom.rc add bar};
my $output = qx{../task rc:custom.rc foo 2>&1};

View File

@@ -111,25 +111,52 @@ unlike ($output, qr/six/, 'g6');
unlike ($output, qr/seven/, 'g7');
$output = qx{../task rc:filter.rc list -tag};
unlike ($output, qr/one/, 'h1');
like ($output, qr/two/, 'h2');
like ($output, qr/three/, 'h3');
like ($output, qr/four/, 'h4');
unlike ($output, qr/five/, 'h5');
like ($output, qr/six/, 'h6');
like ($output, qr/seven/, 'h7');
unlike ($output, qr/one/, 'g1');
like ($output, qr/two/, 'g2');
like ($output, qr/three/, 'g3');
like ($output, qr/four/, 'g4');
unlike ($output, qr/five/, 'g5');
like ($output, qr/six/, 'g6');
like ($output, qr/seven/, 'g7');
$output = qx{../task rc:filter.rc list -missing};
like ($output, qr/one/, 'i1');
like ($output, qr/two/, 'i2');
like ($output, qr/three/, 'i3');
like ($output, qr/four/, 'i4');
like ($output, qr/five/, 'i5');
like ($output, qr/six/, 'i6');
like ($output, qr/seven/, 'i7');
like ($output, qr/one/, 'g1');
like ($output, qr/two/, 'g2');
like ($output, qr/three/, 'g3');
like ($output, qr/four/, 'g4');
like ($output, qr/five/, 'g5');
like ($output, qr/six/, 'g6');
like ($output, qr/seven/, 'g7');
$output = qx{../task rc:filter.rc list +tag -tag};
unlike ($output, qr/one/, 'j1');
unlike ($output, qr/one/, 'g1');
unlike ($output, qr/two/, 'g2');
unlike ($output, qr/three/, 'g3');
unlike ($output, qr/four/, 'g4');
unlike ($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');
@@ -137,25 +164,25 @@ unlike ($output, qr/five/, 'j5');
unlike ($output, qr/six/, 'j6');
unlike ($output, qr/seven/, 'j7');
$output = qx{../task rc:filter.rc list project:A priority:H};
$output = qx{../task rc:filter.rc list project:A +tag};
like ($output, qr/one/, 'k1');
like ($output, qr/two/, 'k2');
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:};
unlike ($output, qr/one/, 'l1');
$output = qx{../task rc:filter.rc list project:A priority:H foo};
like ($output, qr/one/, 'l1');
unlike ($output, qr/two/, 'l2');
like ($output, qr/three/, 'l3');
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 foo};
$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');
@@ -164,7 +191,7 @@ unlike ($output, qr/five/, 'm5');
unlike ($output, qr/six/, 'm6');
unlike ($output, qr/seven/, 'm7');
$output = qx{../task rc:filter.rc list project:A +tag};
$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');
@@ -173,41 +200,14 @@ 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};
like ($output, qr/one/, 'o1');
unlike ($output, qr/two/, 'o2');
unlike ($output, qr/three/, 'o3');
unlike ($output, qr/four/, 'o4');
unlike ($output, qr/five/, 'o5');
unlike ($output, qr/six/, 'o6');
unlike ($output, qr/seven/, 'o7');
$output = qx{../task rc:filter.rc list project:A priority:H +tag};
like ($output, qr/one/, 'p1');
unlike ($output, qr/two/, 'p2');
unlike ($output, qr/three/, 'p3');
unlike ($output, qr/four/, 'p4');
unlike ($output, qr/five/, 'p5');
unlike ($output, qr/six/, 'p6');
unlike ($output, qr/seven/, 'p7');
$output = qx{../task rc:filter.rc list project:A priority:H foo +tag};
like ($output, qr/one/, 'q1');
unlike ($output, qr/two/, 'q2');
unlike ($output, qr/three/, 'q3');
unlike ($output, qr/four/, 'q4');
unlike ($output, qr/five/, 'q5');
unlike ($output, qr/six/, 'q6');
unlike ($output, qr/seven/, 'q7');
$output = qx{../task rc:filter.rc list project:A priority:H foo +tag baz};
unlike ($output, qr/one/, 'r1');
unlike ($output, qr/two/, 'r2');
unlike ($output, qr/three/, 'r3');
unlike ($output, qr/four/, 'r4');
unlike ($output, qr/five/, 'r5');
unlike ($output, qr/six/, 'r6');
unlike ($output, qr/seven/, 'r7');
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';