Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f243f0ed44 | ||
|
|
b305cc0a60 | ||
|
|
53609b2837 | ||
|
|
bdaa0f89d9 | ||
|
|
2fd8d8aa83 | ||
|
|
e69fb81b2b | ||
|
|
d2aa0f31b0 | ||
|
|
05f67db429 | ||
|
|
62be3f8acb | ||
|
|
cc5c99c0a1 | ||
|
|
35792e7874 | ||
|
|
083407f789 | ||
|
|
e1146cdd20 | ||
|
|
f04205be4c | ||
|
|
07da2396fc | ||
|
|
ec7f7cc939 | ||
|
|
1b28d8714b | ||
|
|
79f59f12ae | ||
|
|
f595bc4731 | ||
|
|
972efc58f4 | ||
|
|
dc9ba6d6b8 | ||
|
|
a7196ca181 | ||
|
|
1355571876 | ||
|
|
d3fcd40279 | ||
|
|
c4dcdbff0f | ||
|
|
d39e45841d | ||
|
|
b28575625e | ||
|
|
fc8f8957c4 | ||
|
|
0499bfff49 | ||
|
|
af49ccf508 | ||
|
|
7b0edfdeba | ||
|
|
e5d56e3075 | ||
|
|
ede746ba16 | ||
|
|
0bad0277fe | ||
|
|
8488cbd1a6 | ||
|
|
6f9356da64 | ||
|
|
90d53245c3 | ||
|
|
1422a15cbc | ||
|
|
9c15457d7f | ||
|
|
20d8124a1d | ||
|
|
db6de54ccc | ||
|
|
eb864820cf | ||
|
|
0291e4c72e | ||
|
|
6e27feb8a3 | ||
|
|
1dcba4619e | ||
|
|
7538b43c68 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -15,5 +15,4 @@ www.xls
|
||||
src/tests/all.log
|
||||
src/tests/*.data
|
||||
*~
|
||||
movie*
|
||||
.*.swp
|
||||
|
||||
4
AUTHORS
4
AUTHORS
@@ -17,6 +17,7 @@ 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
|
||||
@@ -34,6 +35,7 @@ Thanks to the following, who submitted detailed bug reports and excellent sugges
|
||||
Eric Farris
|
||||
Bruce Dillahunty
|
||||
Askme Too
|
||||
Mike Adonay
|
||||
Thomas@BIC
|
||||
Ian Mortimer
|
||||
|
||||
Zach Frazier
|
||||
|
||||
54
ChangeLog
54
ChangeLog
@@ -1,7 +1,55 @@
|
||||
|
||||
------ current release ---------------------------
|
||||
|
||||
1.8.0 (7/21/2009)
|
||||
1.8.2 (9/7/2009)
|
||||
+ Added feature #282 that returns useful exit codes to the shell. Now a
|
||||
script can detect whether no tasks were returned by a report (thanks to
|
||||
Pietro Cerutti).
|
||||
+ Fixed bug #287 that causes color control codes to be written to shadow
|
||||
files (thanks to Richard Querin).
|
||||
+ Fixed bug #289 which imported task from todo.sh without valid uuids
|
||||
(thanks to Ben Jackson).
|
||||
+ Fixed bug #291 which generated a false warning about an unrecognized
|
||||
variable when enabling default.projects in .taskrc (thanks to Thomas@BIC).
|
||||
+ Fixed bug #288 which failed to propagate rc file overrides on the command
|
||||
line to the default command (thanks to Zach Frazier).
|
||||
|
||||
------ old releases ------------------------------
|
||||
|
||||
1.8.1 (8/20/2009) 35792e7874d2bb664abb1a0a67960b7fe7e0fccf
|
||||
+ 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).
|
||||
|
||||
1.8.0 (7/21/2009) 14977ef317bd004dae2f2c313e806af9f2a2140c
|
||||
+ 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).
|
||||
@@ -70,9 +118,7 @@
|
||||
and completed tasks.
|
||||
+ Now over 1,600 unit tests, helping to maintain code quality.
|
||||
|
||||
------ old releases ------------------------------
|
||||
|
||||
1.7.1 (6/8/2009)
|
||||
1.7.1 (6/8/2009) 1422a15cbc470cff590bf06daad20d01fe1b05ef
|
||||
+ 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.
|
||||
|
||||
19
NEWS
19
NEWS
@@ -1,5 +1,5 @@
|
||||
|
||||
New Features in task 1.8.0
|
||||
New Features in task 1.8
|
||||
|
||||
- Attribute modifiers, for precise queries
|
||||
- Improved calendar feature
|
||||
@@ -9,26 +9,23 @@ New Features in task 1.8.0
|
||||
- In addition to being a standard part of Fedora 10 and 11 (yum install task),
|
||||
task is now also a standard part of Cygwin 1.5
|
||||
- There are new demo movies on taskwarrior.org
|
||||
- Shell-friendly exit codes
|
||||
|
||||
Please refer to the ChangeLog file for full details. There are too many to
|
||||
list here.
|
||||
|
||||
Task has been built and tested on the following configurations:
|
||||
|
||||
- OS X 10.5 Leopard
|
||||
- OS X 10.4 Tiger
|
||||
- Fedora Core 11 Leonidas
|
||||
- Fedora Core 10 Cambridge
|
||||
- Ubuntu 9.04 Jaunty Jackalope
|
||||
- Ubuntu 8.10 Intrepid Ibex
|
||||
- Ubuntu 8.04 Hardy Heron
|
||||
- OS X 10.6 Snow Leopard and 10.5 Leopard
|
||||
- Fedora 11 Leonidas and 10 Cambridge
|
||||
- Ubuntu 9.04 Jaunty Jackalope and 8.10 Intrepid Ibex
|
||||
- Slackware 12.2
|
||||
- Arch Linux
|
||||
- Solaris 10
|
||||
- Solaris 8
|
||||
- Gentoo Linux
|
||||
- Solaris 10 and 8
|
||||
- OpenBSD 4.5
|
||||
- FreeBSD
|
||||
- Cygwin 1.5.25-14
|
||||
- Cygwin 1.5
|
||||
|
||||
While Task has undergone testing, bugs are sure to remain. If you encounter a
|
||||
bug, please enter a new issue at:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.61)
|
||||
AC_INIT(task, 1.8.0, support@taskwarrior.org)
|
||||
AC_INIT(task, 1.8.2, support@taskwarrior.org)
|
||||
|
||||
CFLAGS="${CFLAGS=}"
|
||||
CXXFLAGS="${CXXFLAGS=}"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.TH task-tutorial 5 2009-07-14 "Task 1.8.0" "User Manuals"
|
||||
.TH task-tutorial 5 2009-09-07 "task 1.8.2" "User Manuals"
|
||||
|
||||
.SH NAME
|
||||
task-tutorial \- A tutorial for the task(1) command line todo manager.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.TH task 1 2009-07-14 "Task 1.8.0" "User Manuals"
|
||||
.TH task 1 2009-09-07 "task 1.8.2" "User Manuals"
|
||||
|
||||
.SH NAME
|
||||
task \- A command line todo manager.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.TH taskrc 5 2009-07-14 "Task 1.8.0" "User Manuals"
|
||||
.TH taskrc 5 2009-09-07 "task 1.8.2" "User Manuals"
|
||||
|
||||
.SH NAME
|
||||
taskrc \- Configuration file for the task(1) command
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# setup.hint for task 1.7.1-1
|
||||
# setup.hint for task 1.8.1-1
|
||||
category: Utils
|
||||
requires: libncurses9 cygwin
|
||||
sdesc: A command-line to do list manager
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
task 1.7.1-1
|
||||
task 1.8.1-1
|
||||
------------------------------------------
|
||||
|
||||
A command-line to do list manager that can be used
|
||||
@@ -28,10 +28,10 @@ Language:
|
||||
------------------------------------
|
||||
|
||||
Build instructions:
|
||||
unpack task-1.7.1-1-src.tar.bz2
|
||||
unpack task-1.8.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.7.1-1
|
||||
cd /usr/src/task-1.8.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.7.1-1 -- 2009-06-17 ----
|
||||
---- task-1.8.1-1 -- 2009-08-20 ----
|
||||
@@ -1,8 +1,8 @@
|
||||
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
|
||||
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
|
||||
@@ -0,0 +1,10 @@
|
||||
+# setup.hint for task 1.7.1-1
|
||||
+# setup.hint for task 1.8.1-1
|
||||
+category: Utils
|
||||
+requires: libncurses9 cygwin
|
||||
+sdesc: A command-line to do list manager
|
||||
@@ -12,11 +12,11 @@ diff -Nrup task-1.7.1-1/CYGWIN-PATCHES/setup.hint task-1.7.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.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
|
||||
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
|
||||
@@ -0,0 +1,45 @@
|
||||
+task 1.7.1-1
|
||||
+task 1.8.1-1
|
||||
+------------------------------------------
|
||||
+
|
||||
+A command-line to do list manager that can be used
|
||||
@@ -46,10 +46,10 @@ diff -Nrup task-1.7.1-1/CYGWIN-PATCHES/task-1.7.1-1.README task-1.7.1-1.cygwin/C
|
||||
+------------------------------------
|
||||
+
|
||||
+Build instructions:
|
||||
+ unpack task-1.7.1-1-src.tar.bz2
|
||||
+ unpack task-1.8.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.7.1-1
|
||||
+ cd /usr/src/task-1.8.1-1
|
||||
+ ./configure --prefix=/usr
|
||||
+ make
|
||||
+ make install
|
||||
@@ -60,4 +60,4 @@ diff -Nrup task-1.7.1-1/CYGWIN-PATCHES/task-1.7.1-1.README task-1.7.1-1.cygwin/C
|
||||
+Federico Hernandez <ultrafredde@gmail.com> and
|
||||
+is licensed under the GPL
|
||||
+
|
||||
+---- task-1.7.1-1 -- 2009-06-17 ----
|
||||
+---- task-1.8.1-1 -- 2009-08-20 ----
|
||||
@@ -1,4 +1,4 @@
|
||||
task 1.7.1-1
|
||||
task 1.8.1-1
|
||||
------------------------------------------
|
||||
|
||||
A command-line to do list manager that can be used
|
||||
@@ -28,10 +28,10 @@ Language:
|
||||
------------------------------------
|
||||
|
||||
Build instructions:
|
||||
unpack task-1.7.1-1-src.tar.bz2
|
||||
unpack task-1.8.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.7.1-1
|
||||
cd /usr/src/task-1.8.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.7.1-1 -- 2009-06-17 ----
|
||||
---- task-1.8.1-1 -- 2009-08-20 ----
|
||||
@@ -1,6 +1,6 @@
|
||||
Name: task
|
||||
Version: 1.8.0
|
||||
Release: 0%{?dist}
|
||||
Version: 1.8.1
|
||||
Release: 1%{?dist}
|
||||
Summary: A command-line to do list manager
|
||||
|
||||
Group: Applications/Productivity
|
||||
@@ -40,18 +40,25 @@ rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
%doc AUTHORS ChangeLog COPYING NEWS README scripts
|
||||
%doc AUTHORS ChangeLog COPYING NEWS README scripts i18n
|
||||
%{_bindir}/task
|
||||
%{_mandir}/man1/task.1.gz
|
||||
%{_mandir}/man5/taskrc.5.gz
|
||||
%{_mandir}/man5/task-tutorial.5.gz
|
||||
%{_sysconfdir}/bash_completion.d
|
||||
%config(noreplace) %{_sysconfdir}/bash_completion.d
|
||||
|
||||
|
||||
%changelog
|
||||
* Mon Jun 15 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.8.0-0
|
||||
* 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
|
||||
Intial RPM for task release 1.8.0
|
||||
Installs now bash_completion file
|
||||
* 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
|
||||
* 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
|
||||
|
||||
@@ -1,8 +1,32 @@
|
||||
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> Thu, 11 Jun 2009 23:02:28 +0200
|
||||
-- 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
|
||||
|
||||
task (1.7.1-0ubuntu1) jaunty; urgency=low
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
This package was debianized by:
|
||||
|
||||
Federico Hernandez <ultrafredde@gmail.com> on Thu, 11 Jun 2009 23:02:28 +0200
|
||||
Federico Hernandez <ultrafredde@gmail.com> on Thu, 20 Aug 2009 20:26:33 +0200
|
||||
|
||||
It was downloaded from:
|
||||
|
||||
@@ -9,6 +9,9 @@ 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
|
||||
@@ -17,18 +20,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:
|
||||
|
||||
|
||||
2
package-config/ubuntu/debian/examples
Normal file
2
package-config/ubuntu/debian/examples
Normal file
@@ -0,0 +1,2 @@
|
||||
scripts
|
||||
i18n
|
||||
@@ -31,8 +31,9 @@ binary-arch: install
|
||||
dh_installchangelogs
|
||||
dh_installdocs
|
||||
dh_installman
|
||||
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_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
|
||||
dh_strip
|
||||
dh_compress
|
||||
dh_fixperms
|
||||
|
||||
@@ -48,10 +48,6 @@
|
||||
# http://taskwarrior.org
|
||||
#
|
||||
|
||||
_task_get_projects() {
|
||||
task _projects
|
||||
}
|
||||
|
||||
_task_get_tags() {
|
||||
task _tags
|
||||
}
|
||||
@@ -60,6 +56,10 @@ _task_get_config() {
|
||||
task _config
|
||||
}
|
||||
|
||||
_task_offer_projects() {
|
||||
COMPREPLY=( $(compgen -W "$(task _projects)" -- ${cur/*:/}) )
|
||||
}
|
||||
|
||||
_task()
|
||||
{
|
||||
local cur prev opts base
|
||||
@@ -67,34 +67,61 @@ _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 "${cur}" in
|
||||
pro*:*)
|
||||
local projects=$(_task_get_projects)
|
||||
local partial_project="${cur/*:/}"
|
||||
COMPREPLY=( $(compgen -W "${projects}" -- ${partial_project}) )
|
||||
return 0
|
||||
case "${prev}" in
|
||||
:)
|
||||
case "${prev2}" 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 's/^/rc\./')
|
||||
COMPREPLY=( $(compgen -W "${config}" -- ${cur}) )
|
||||
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
|
||||
;;
|
||||
esac
|
||||
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
}
|
||||
complete -F _task task
|
||||
complete -o nospace -F _task task
|
||||
|
||||
27
src/Att.cpp
27
src/Att.cpp
@@ -407,6 +407,17 @@ 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
|
||||
@@ -461,7 +472,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.
|
||||
/* TODO This might be too slow to include. Test this assumption.
|
||||
validNameValue (mName, mMod, mValue);
|
||||
*/
|
||||
}
|
||||
@@ -711,8 +722,11 @@ 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, """); // no i18n
|
||||
value.replace (i, 1, "&dquot;"); // no i18n
|
||||
|
||||
while ((i = value.find (',')) != std::string::npos)
|
||||
value.replace (i, 1, ","); // no i18n
|
||||
@@ -730,7 +744,8 @@ void Att::encode (std::string& value) const
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Decode values after parse.
|
||||
// \t <- &tab;
|
||||
// " <- "
|
||||
// " <- " or &dquot;
|
||||
// ' <- &squot;
|
||||
// , <- ,
|
||||
// [ <- &open;
|
||||
// ] <- &close;
|
||||
@@ -742,6 +757,12 @@ 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 (""")) != std::string::npos) // no i18n
|
||||
value.replace (i, 6, "\"");
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ 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;
|
||||
|
||||
178
src/Context.cpp
178
src/Context.cpp
@@ -49,6 +49,7 @@ Context::Context ()
|
||||
, tdb ()
|
||||
, stringtable ()
|
||||
, program ("")
|
||||
, overrides ("")
|
||||
, cmd ()
|
||||
, inShadow (false)
|
||||
{
|
||||
@@ -126,98 +127,110 @@ void Context::initialize ()
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int Context::run ()
|
||||
{
|
||||
int rc;
|
||||
Timer t ("Context::run");
|
||||
|
||||
std::string output;
|
||||
try
|
||||
{
|
||||
parse (); // Parse command line.
|
||||
output = dispatch (); // Dispatch to command handlers.
|
||||
parse (); // Parse command line.
|
||||
rc = dispatch (output); // Dispatch to command handlers.
|
||||
}
|
||||
|
||||
catch (const std::string& error)
|
||||
{
|
||||
footnote (error);
|
||||
rc = 2;
|
||||
}
|
||||
|
||||
catch (...)
|
||||
{
|
||||
footnote (stringtable.get (100, "Unknown error."));
|
||||
rc = 3;
|
||||
}
|
||||
|
||||
// Dump all debug messages.
|
||||
if (config.get (std::string ("debug"), false))
|
||||
foreach (d, debugMessages)
|
||||
std::cout << colorizeDebug (*d) << std::endl;
|
||||
if (config.get ("color", true) || config.get (std::string ("_forcecolor"), false))
|
||||
std::cout << colorizeDebug (*d) << std::endl;
|
||||
else
|
||||
std::cout << *d << std::endl;
|
||||
|
||||
// Dump all headers.
|
||||
foreach (h, headers)
|
||||
std::cout << colorizeHeader (*h) << std::endl;
|
||||
if (config.get ("color", true) || config.get (std::string ("_forcecolor"), false))
|
||||
std::cout << colorizeHeader (*h) << std::endl;
|
||||
else
|
||||
std::cout << *h << std::endl;
|
||||
|
||||
// Dump the report output.
|
||||
std::cout << output;
|
||||
|
||||
// Dump all footnotes.
|
||||
foreach (f, footnotes)
|
||||
std::cout << colorizeFootnote (*f) << std::endl;
|
||||
if (config.get ("color", true) || config.get (std::string ("_forcecolor"), false))
|
||||
std::cout << colorizeFootnote (*f) << std::endl;
|
||||
else
|
||||
std::cout << *f << std::endl;
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Context::dispatch ()
|
||||
int Context::dispatch (std::string &out)
|
||||
{
|
||||
int rc = 0;
|
||||
Timer t ("Context::dispatch");
|
||||
|
||||
// TODO Just look at this thing. It cries out for a dispatch table.
|
||||
std::string out;
|
||||
if (cmd.command == "projects") { out = handleProjects (); }
|
||||
else if (cmd.command == "tags") { out = handleTags (); }
|
||||
else if (cmd.command == "colors") { out = handleColor (); }
|
||||
else if (cmd.command == "version") { out = handleVersion (); }
|
||||
else if (cmd.command == "help") { out = longUsage (); }
|
||||
else if (cmd.command == "stats") { out = handleReportStats (); }
|
||||
else if (cmd.command == "info") { out = handleInfo (); }
|
||||
else if (cmd.command == "history") { out = handleReportHistory (); }
|
||||
else if (cmd.command == "ghistory") { out = handleReportGHistory (); }
|
||||
else if (cmd.command == "summary") { out = handleReportSummary (); }
|
||||
else if (cmd.command == "calendar") { out = handleReportCalendar (); }
|
||||
else if (cmd.command == "timesheet") { out = handleReportTimesheet (); }
|
||||
else if (cmd.command == "add") { out = handleAdd (); }
|
||||
else if (cmd.command == "append") { out = handleAppend (); }
|
||||
else if (cmd.command == "annotate") { out = handleAnnotate (); }
|
||||
else if (cmd.command == "done") { out = handleDone (); }
|
||||
else if (cmd.command == "delete") { out = handleDelete (); }
|
||||
else if (cmd.command == "start") { out = handleStart (); }
|
||||
else if (cmd.command == "stop") { out = handleStop (); }
|
||||
else if (cmd.command == "export") { out = handleExport (); }
|
||||
else if (cmd.command == "import") { out = handleImport (); }
|
||||
else if (cmd.command == "duplicate") { out = handleDuplicate (); }
|
||||
else if (cmd.command == "edit") { out = handleEdit (); }
|
||||
if (cmd.command == "projects") { rc = handleProjects (out); }
|
||||
else if (cmd.command == "tags") { rc = handleTags (out); }
|
||||
else if (cmd.command == "colors") { rc = handleColor (out); }
|
||||
else if (cmd.command == "version") { rc = handleVersion (out); }
|
||||
else if (cmd.command == "help") { rc = longUsage (out); }
|
||||
else if (cmd.command == "stats") { rc = handleReportStats (out); }
|
||||
else if (cmd.command == "info") { rc = handleInfo (out); }
|
||||
else if (cmd.command == "history") { rc = handleReportHistory (out); }
|
||||
else if (cmd.command == "ghistory") { rc = handleReportGHistory (out); }
|
||||
else if (cmd.command == "summary") { rc = handleReportSummary (out); }
|
||||
else if (cmd.command == "calendar") { rc = handleReportCalendar (out); }
|
||||
else if (cmd.command == "timesheet") { rc = handleReportTimesheet (out); }
|
||||
else if (cmd.command == "add") { rc = handleAdd (out); }
|
||||
else if (cmd.command == "append") { rc = handleAppend (out); }
|
||||
else if (cmd.command == "annotate") { rc = handleAnnotate (out); }
|
||||
else if (cmd.command == "done") { rc = handleDone (out); }
|
||||
else if (cmd.command == "delete") { rc = handleDelete (out); }
|
||||
else if (cmd.command == "start") { rc = handleStart (out); }
|
||||
else if (cmd.command == "stop") { rc = handleStop (out); }
|
||||
else if (cmd.command == "export") { rc = handleExport (out); }
|
||||
else if (cmd.command == "import") { rc = handleImport (out); }
|
||||
else if (cmd.command == "duplicate") { rc = handleDuplicate (out); }
|
||||
else if (cmd.command == "edit") { rc = handleEdit (out); }
|
||||
#ifdef FEATURE_SHELL
|
||||
else if (cmd.command == "shell") { handleShell (); }
|
||||
else if (cmd.command == "shell") { handleShell ( ); }
|
||||
#endif
|
||||
else if (cmd.command == "undo") { handleUndo (); }
|
||||
else if (cmd.command == "_projects") { out = handleCompletionProjects (); }
|
||||
else if (cmd.command == "_tags") { out = handleCompletionTags (); }
|
||||
else if (cmd.command == "_commands") { out = handleCompletionCommands (); }
|
||||
else if (cmd.command == "_ids") { out = handleCompletionIDs (); }
|
||||
else if (cmd.command == "_config") { out = handleCompletionConfig (); }
|
||||
else if (cmd.command == "undo") { handleUndo ( ); }
|
||||
else if (cmd.command == "_projects") { rc = handleCompletionProjects (out); }
|
||||
else if (cmd.command == "_tags") { rc = handleCompletionTags (out); }
|
||||
else if (cmd.command == "_commands") { rc = handleCompletionCommands (out); }
|
||||
else if (cmd.command == "_ids") { rc = handleCompletionIDs (out); }
|
||||
else if (cmd.command == "_config") { rc = handleCompletionConfig (out); }
|
||||
else if (cmd.command == "" &&
|
||||
sequence.size ()) { out = handleModify (); }
|
||||
sequence.size ()) { rc = handleModify (out); }
|
||||
|
||||
// Command that display IDs and therefore need TDB::gc first.
|
||||
else if (cmd.command == "next") { if (!inShadow) tdb.gc (); out = handleReportNext (); }
|
||||
else if (cmd.validCustom (cmd.command)) { if (!inShadow) tdb.gc (); out = handleCustomReport (cmd.command); }
|
||||
else if (cmd.command == "next") { if (!inShadow) tdb.gc (); rc = handleReportNext (out); }
|
||||
else if (cmd.validCustom (cmd.command)) { if (!inShadow) tdb.gc (); rc = handleCustomReport (cmd.command, out); }
|
||||
|
||||
// If the command is not recognized, display usage.
|
||||
else { out = shortUsage (); }
|
||||
else { rc = shortUsage (out); }
|
||||
|
||||
// Only update the shadow file if such an update was not suppressed (shadow),
|
||||
if (cmd.isWriteCommand () && !inShadow)
|
||||
shadow ();
|
||||
|
||||
return out;
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -243,8 +256,6 @@ void Context::shadow ()
|
||||
|
||||
std::string oldCurses = config.get ("curses");
|
||||
std::string oldColor = config.get ("color");
|
||||
config.set ("curses", "off");
|
||||
config.set ("color", "off");
|
||||
|
||||
clear ();
|
||||
|
||||
@@ -255,8 +266,12 @@ void Context::shadow ()
|
||||
split (args, command, ' ');
|
||||
|
||||
initialize ();
|
||||
config.set ("curses", "off");
|
||||
config.set ("color", "off");
|
||||
|
||||
parse ();
|
||||
std::string result = dispatch ();
|
||||
std::string result;
|
||||
(void)dispatch (result);
|
||||
std::ofstream out (shadowFile.c_str ());
|
||||
if (out.good ())
|
||||
{
|
||||
@@ -307,6 +322,18 @@ 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 ()
|
||||
{
|
||||
@@ -330,6 +357,14 @@ 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;
|
||||
@@ -358,13 +393,19 @@ void Context::loadCorrectConfigFile ()
|
||||
}
|
||||
|
||||
// Do we need to create a default rc?
|
||||
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 (access (rc.c_str (), F_OK))
|
||||
{
|
||||
config.createDefaultRC (rc, data);
|
||||
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.");
|
||||
}
|
||||
|
||||
// Create data location, if necessary.
|
||||
@@ -398,6 +439,7 @@ void Context::loadCorrectConfigFile ()
|
||||
n.getUntilEOS (value))
|
||||
{
|
||||
config.set (name, value);
|
||||
overrides += " " + *arg;
|
||||
footnote (std::string ("Configuration override ") + // TODO i18n
|
||||
arg->substr (3, std::string::npos));
|
||||
}
|
||||
@@ -528,7 +570,12 @@ void Context::parse (
|
||||
attribute.mod (mod);
|
||||
attribute.value (value);
|
||||
|
||||
parseTask[attribute.name ()] = attribute;
|
||||
// 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;
|
||||
}
|
||||
|
||||
// *arg has the appearance of an attribute (foo:bar), but isn't
|
||||
@@ -609,12 +656,13 @@ void Context::parse (
|
||||
// then invoke the default command.
|
||||
if (parseCmd.command == "" && parseArgs.size () == 0)
|
||||
{
|
||||
std::string defaultCommand = config.get ("default.command");
|
||||
// Apply overrides, if any.
|
||||
std::string defaultCommand = config.get ("default.command") + overrides;
|
||||
if (defaultCommand != "")
|
||||
{
|
||||
// Stuff the command line.
|
||||
parseArgs.clear ();
|
||||
split (parseArgs, defaultCommand, ' ');
|
||||
args.clear ();
|
||||
split (args, defaultCommand, ' ');
|
||||
header ("[task " + defaultCommand + "]");
|
||||
|
||||
// Reinitialize the context and recurse.
|
||||
@@ -657,46 +705,46 @@ void Context::autoFilter (Task& t, Filter& f)
|
||||
foreach (att, t)
|
||||
{
|
||||
// Words are found in the description using the .has modifier.
|
||||
if (att->first == "description" && att->second.mod () == "")
|
||||
if (att->second.name () == "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->first + ".has:" + *word);
|
||||
debug ("auto filter: " + att->second.name () + ".has:" + *word);
|
||||
}
|
||||
}
|
||||
|
||||
// Projects are matched left-most.
|
||||
else if (att->first == "project" && att->second.mod () == "")
|
||||
else if (att->second.name () == "project" && att->second.mod () == "")
|
||||
{
|
||||
if (att->second.value () != "")
|
||||
{
|
||||
f.push_back (Att ("project", "startswith", att->second.value ()));
|
||||
debug ("auto filter: " + att->first + ".startswith:" + att->second.value ());
|
||||
debug ("auto filter: " + att->second.name () + ".startswith:" + att->second.value ());
|
||||
}
|
||||
else
|
||||
{
|
||||
f.push_back (Att ("project", "is", att->second.value ()));
|
||||
debug ("auto filter: " + att->first + ".is:" + att->second.value ());
|
||||
debug ("auto filter: " + att->second.name () + ".is:" + att->second.value ());
|
||||
}
|
||||
}
|
||||
|
||||
// The limit attribute does not participate in filtering, and needs to be
|
||||
// specifically handled in handleCustomReport.
|
||||
else if (att->first == "limit")
|
||||
else if (att->second.name () == "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->first == "uuid")
|
||||
else if (att->second.name () == "uuid")
|
||||
{
|
||||
}
|
||||
|
||||
// The mechanism for filtering on tags is +/-<tag>.
|
||||
else if (att->first == "tags")
|
||||
else if (att->second.name () == "tags")
|
||||
{
|
||||
}
|
||||
|
||||
@@ -705,7 +753,7 @@ void Context::autoFilter (Task& t, Filter& f)
|
||||
{
|
||||
f.push_back (att->second);
|
||||
debug ("auto filter: " +
|
||||
att->first +
|
||||
att->second.name () +
|
||||
(att->second.mod () != "" ?
|
||||
("." + att->second.mod () + ":") :
|
||||
":") +
|
||||
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
void initialize (); // for reinitializing
|
||||
int run (); // task classic
|
||||
int interactive (); // task interactive (not implemented)
|
||||
std::string dispatch (); // command handler dispatch
|
||||
int dispatch (std::string&); // command handler dispatch
|
||||
void shadow (); // shadow file update
|
||||
|
||||
int getWidth (); // determine terminal width
|
||||
@@ -65,6 +65,7 @@ public:
|
||||
void clear ();
|
||||
|
||||
std::string canonicalize (const std::string&) const;
|
||||
void disallowModification () const;
|
||||
|
||||
private:
|
||||
void loadCorrectConfigFile ();
|
||||
@@ -82,6 +83,7 @@ public:
|
||||
StringTable stringtable;
|
||||
std::string program;
|
||||
std::vector <std::string> args;
|
||||
std::string overrides;
|
||||
Cmd cmd;
|
||||
std::map <std::string, std::string> aliases;
|
||||
std::vector <std::string> tagAdditions;
|
||||
|
||||
@@ -51,12 +51,6 @@ Duration::Duration (const std::string& input)
|
||||
parse (input);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Duration::operator int ()
|
||||
{
|
||||
return (int) mDays;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Duration::operator time_t ()
|
||||
{
|
||||
|
||||
@@ -40,7 +40,6 @@ public:
|
||||
bool operator> (const Duration&);
|
||||
~Duration (); // Destructor
|
||||
|
||||
operator int ();
|
||||
operator time_t ();
|
||||
operator std::string ();
|
||||
|
||||
|
||||
@@ -40,37 +40,51 @@ bool Filter::pass (const Record& record) const
|
||||
// First do description/annotation matches.
|
||||
foreach (att, (*this))
|
||||
{
|
||||
// Descriptions have special handling.
|
||||
// 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.
|
||||
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 ())
|
||||
{
|
||||
// A description match failure can be salvaged by an annotation match.
|
||||
if (! att->match (r->second))
|
||||
{
|
||||
bool annoMatch = false;
|
||||
foreach (ra, record)
|
||||
{
|
||||
if (ra->first.length () > 11 &&
|
||||
ra->first.substr (0, 11) == "annotation_")
|
||||
{
|
||||
if (att->match (ra->second))
|
||||
{
|
||||
annoMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
description_result = att->match (r->second);
|
||||
|
||||
if (!annoMatch)
|
||||
return false;
|
||||
foreach (ra, record)
|
||||
{
|
||||
if (ra->first.length () > 11 &&
|
||||
ra->first.substr (0, 11) == "annotation_")
|
||||
{
|
||||
if (att->match (ra->second))
|
||||
++annotation_pass_count;
|
||||
else
|
||||
++annotation_fail_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
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.
|
||||
// Annotations are skipped, because they are handled above.
|
||||
else if (att->name ().length () > 11 &&
|
||||
att->name ().substr (0, 11) == "annotation_")
|
||||
{
|
||||
|
||||
@@ -67,8 +67,8 @@ bool Task::operator== (const Task& other)
|
||||
return false;
|
||||
|
||||
foreach (att, *this)
|
||||
if (att->first != "uuid")
|
||||
if (att->second.value () != other.get (att->first))
|
||||
if (att->second.name () != "uuid")
|
||||
if (att->second.value () != other.get (att->second.name ()))
|
||||
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
|
||||
|
||||
|
||||
169
src/command.cpp
169
src/command.cpp
@@ -49,7 +49,7 @@
|
||||
extern Context context;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleAdd ()
|
||||
int handleAdd (std::string &outs)
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
@@ -84,6 +84,15 @@ 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 ();
|
||||
|
||||
@@ -101,19 +110,20 @@ std::string handleAdd ()
|
||||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleProjects ()
|
||||
int handleProjects (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
std::stringstream out;
|
||||
|
||||
context.filter.push_back (Att ("status", "pending"));
|
||||
|
||||
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 ();
|
||||
@@ -187,19 +197,21 @@ std::string handleProjects ()
|
||||
<< " (" << quantity << (quantity == 1 ? " task" : " tasks") << ")"
|
||||
<< std::endl;
|
||||
}
|
||||
else
|
||||
else {
|
||||
out << "No projects."
|
||||
<< std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleCompletionProjects ()
|
||||
int handleCompletionProjects (std::string &outs)
|
||||
{
|
||||
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))
|
||||
@@ -221,19 +233,20 @@ std::string handleCompletionProjects ()
|
||||
if (project->first.length ())
|
||||
out << project->first << std::endl;
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleTags ()
|
||||
int handleTags (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
std::stringstream out;
|
||||
|
||||
context.filter.push_back (Att ("status", "pending"));
|
||||
|
||||
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 ();
|
||||
@@ -284,19 +297,22 @@ std::string handleTags ()
|
||||
<< " (" << quantity << (quantity == 1 ? " task" : " tasks") << ")"
|
||||
<< std::endl;
|
||||
}
|
||||
else
|
||||
else {
|
||||
out << "No tags."
|
||||
<< std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleCompletionTags ()
|
||||
int handleCompletionTags (std::string &outs)
|
||||
{
|
||||
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))
|
||||
@@ -323,11 +339,12 @@ std::string handleCompletionTags ()
|
||||
foreach (tag, unique)
|
||||
out << tag->first << std::endl;
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleCompletionCommands ()
|
||||
int handleCompletionCommands (std::string &outs)
|
||||
{
|
||||
std::vector <std::string> commands;
|
||||
context.cmd.allCommands (commands);
|
||||
@@ -337,11 +354,12 @@ std::string handleCompletionCommands ()
|
||||
foreach (command, commands)
|
||||
out << *command << std::endl;
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleCompletionConfig ()
|
||||
int handleCompletionConfig (std::string &outs)
|
||||
{
|
||||
std::vector <std::string> configs;
|
||||
context.config.all (configs);
|
||||
@@ -351,15 +369,15 @@ std::string handleCompletionConfig ()
|
||||
foreach (config, configs)
|
||||
out << *config << std::endl;
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleCompletionIDs ()
|
||||
int handleCompletionIDs (std::string &outs)
|
||||
{
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
handleRecurrence ();
|
||||
Filter filter;
|
||||
context.tdb.loadPending (tasks, filter);
|
||||
context.tdb.commit ();
|
||||
@@ -377,20 +395,24 @@ std::string handleCompletionIDs ()
|
||||
foreach (id, ids)
|
||||
out << *id << std::endl;
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void handleUndo ()
|
||||
{
|
||||
context.disallowModification ();
|
||||
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.undo ();
|
||||
context.tdb.unlock ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleVersion ()
|
||||
int handleVersion (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
std::stringstream out;
|
||||
|
||||
// Create a table for the disclaimer.
|
||||
@@ -477,8 +499,8 @@ std::string handleVersion ()
|
||||
" blanklines bulk color color.active color.due color.overdue color.pri.H "
|
||||
"color.pri.L color.pri.M color.pri.none color.recurring color.tagged "
|
||||
"color.footnote color.header color.debug confirmation curses data.location "
|
||||
"dateformat debug default.command default.priority defaultwidth due locale "
|
||||
"displayweeknumber echo.command locking monthsperline nag next project "
|
||||
"dateformat debug default.command default.priority default.project defaultwidth "
|
||||
"due locale displayweeknumber echo.command locking monthsperline nag next project "
|
||||
"shadow.command shadow.file shadow.notify weekstart editor import.synonym.id "
|
||||
"import.synonym.uuid longversion complete.all.projects complete.all.tags "
|
||||
#ifdef FEATURE_SHELL
|
||||
@@ -518,7 +540,7 @@ std::string handleVersion ()
|
||||
if (unrecognized.size ())
|
||||
{
|
||||
out << "Your .taskrc file contains these unrecognized variables:"
|
||||
<< std::endl;
|
||||
<< std::endl;
|
||||
|
||||
foreach (i, unrecognized)
|
||||
out << " " << *i << std::endl;
|
||||
@@ -529,9 +551,11 @@ std::string handleVersion ()
|
||||
// Verify installation. This is mentioned in the documentation as the way to
|
||||
// ensure everything is properly installed.
|
||||
|
||||
if (all.size () == 0)
|
||||
if (all.size () == 0) {
|
||||
out << "Configuration error: .taskrc contains no entries"
|
||||
<< std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (context.config.get ("data.location") == "")
|
||||
@@ -545,17 +569,20 @@ std::string handleVersion ()
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleDelete ()
|
||||
int handleDelete (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
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);
|
||||
|
||||
@@ -638,24 +665,29 @@ std::string handleDelete ()
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
else {
|
||||
out << "Task not deleted." << std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
|
||||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleStart ()
|
||||
int handleStart (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
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);
|
||||
|
||||
@@ -691,23 +723,27 @@ std::string handleStart ()
|
||||
<< task->get ("description")
|
||||
<< "' already started."
|
||||
<< std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
|
||||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleStop ()
|
||||
int handleStop (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
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);
|
||||
|
||||
@@ -737,24 +773,26 @@ std::string handleStop ()
|
||||
<< task->get ("description")
|
||||
<< "' not started."
|
||||
<< std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
|
||||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleDone ()
|
||||
int handleDone (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
int count = 0;
|
||||
std::stringstream out;
|
||||
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
handleRecurrence ();
|
||||
Filter filter;
|
||||
context.tdb.loadPending (tasks, filter);
|
||||
|
||||
@@ -818,6 +856,7 @@ std::string handleDone ()
|
||||
<< task->get ("description")
|
||||
<< "' is not pending"
|
||||
<< std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
context.tdb.commit ();
|
||||
@@ -831,11 +870,12 @@ std::string handleDone ()
|
||||
<< " as done"
|
||||
<< std::endl;
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleExport ()
|
||||
int handleExport (std::string &outs)
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
@@ -874,18 +914,18 @@ std::string handleExport ()
|
||||
}
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleModify ()
|
||||
int handleModify (std::string &outs)
|
||||
{
|
||||
int count = 0;
|
||||
std::stringstream out;
|
||||
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
handleRecurrence ();
|
||||
Filter filter;
|
||||
context.tdb.loadPending (tasks, filter);
|
||||
|
||||
@@ -952,18 +992,18 @@ std::string handleModify ()
|
||||
if (context.config.get ("echo.command", true))
|
||||
out << "Modified " << count << " task" << (count == 1 ? "" : "s") << std::endl;
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleAppend ()
|
||||
int handleAppend (std::string &outs)
|
||||
{
|
||||
int count = 0;
|
||||
std::stringstream out;
|
||||
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
handleRecurrence ();
|
||||
Filter filter;
|
||||
context.tdb.loadPending (tasks, filter);
|
||||
|
||||
@@ -1020,11 +1060,12 @@ std::string handleAppend ()
|
||||
if (context.config.get ("echo.command", true))
|
||||
out << "Appended " << count << " task" << (count == 1 ? "" : "s") << std::endl;
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleDuplicate ()
|
||||
int handleDuplicate (std::string &outs)
|
||||
{
|
||||
std::stringstream out;
|
||||
int count = 0;
|
||||
@@ -1089,7 +1130,8 @@ std::string handleDuplicate ()
|
||||
if (context.config.get ("echo.command", true))
|
||||
out << "Duplicated " << count << " task" << (count == 1 ? "" : "s") << std::endl;
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -1168,8 +1210,9 @@ void handleShell ()
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleColor ()
|
||||
int handleColor (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
std::stringstream out;
|
||||
if (context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false))
|
||||
{
|
||||
@@ -1251,13 +1294,15 @@ std::string handleColor ()
|
||||
out << "Color is currently turned off in your .taskrc file. "
|
||||
"To enable color, create the entry 'color=on'."
|
||||
<< std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleAnnotate ()
|
||||
int handleAnnotate (std::string &outs)
|
||||
{
|
||||
if (!context.task.has ("description"))
|
||||
throw std::string ("Cannot apply a blank annotation.");
|
||||
@@ -1301,7 +1346,8 @@ std::string handleAnnotate ()
|
||||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -1359,12 +1405,12 @@ int deltaAttributes (Task& task)
|
||||
|
||||
foreach (att, context.task)
|
||||
{
|
||||
if (att->first != "uuid" &&
|
||||
att->first != "description" &&
|
||||
att->first != "tags")
|
||||
if (att->second.name () != "uuid" &&
|
||||
att->second.name () != "description" &&
|
||||
att->second.name () != "tags")
|
||||
{
|
||||
// Modifying "wait" changes status.
|
||||
if (att->first == "wait")
|
||||
if (att->second.name () == "wait")
|
||||
{
|
||||
if (att->second.value () == "")
|
||||
task.setStatus (Task::pending);
|
||||
@@ -1373,8 +1419,9 @@ int deltaAttributes (Task& task)
|
||||
}
|
||||
|
||||
if (att->second.value () == "")
|
||||
task.remove (att->first);
|
||||
task.remove (att->second.name ());
|
||||
else
|
||||
// One of the few places where the compound attribute name is used.
|
||||
task.set (att->first, att->second.value ());
|
||||
|
||||
++changes;
|
||||
|
||||
@@ -52,7 +52,7 @@ static std::vector <std::string> customReports;
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// This report will eventually become the one report that many others morph into
|
||||
// via the .taskrc file.
|
||||
std::string handleCustomReport (const std::string& report)
|
||||
int handleCustomReport (const std::string& report, std::string &outs)
|
||||
{
|
||||
// Load report configuration.
|
||||
std::string columnList = context.config.get ("report." + report + ".columns");
|
||||
@@ -94,21 +94,24 @@ std::string handleCustomReport (const std::string& report)
|
||||
labelList,
|
||||
sortList,
|
||||
filterList,
|
||||
tasks);
|
||||
tasks,
|
||||
outs);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// This report will eventually become the one report that many others morph into
|
||||
// via the .taskrc file.
|
||||
|
||||
std::string runCustomReport (
|
||||
int runCustomReport (
|
||||
const std::string& report,
|
||||
const std::string& columnList,
|
||||
const std::string& labelList,
|
||||
const std::string& sortList,
|
||||
const std::string& filterList,
|
||||
std::vector <Task>& tasks)
|
||||
std::vector <Task>& tasks,
|
||||
std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
// Load report configuration.
|
||||
std::vector <std::string> columns;
|
||||
split (columns, columnList, ',');
|
||||
@@ -547,11 +550,14 @@ std::string runCustomReport (
|
||||
<< table.rowCount ()
|
||||
<< (table.rowCount () == 1 ? " task" : " tasks")
|
||||
<< std::endl;
|
||||
else
|
||||
else {
|
||||
out << "No matches."
|
||||
<< std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
13
src/edit.cpp
13
src/edit.cpp
@@ -499,7 +499,13 @@ 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));
|
||||
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 ();
|
||||
|
||||
std::stringstream name;
|
||||
name << "annotation_" << when.toEpoch ();
|
||||
std::string text = trim (value.substr (gap, std::string::npos), "\t ");
|
||||
@@ -593,7 +599,7 @@ ARE_THESE_REALLY_HARMFUL:
|
||||
// Introducing the Silver Bullet. This feature is the catch-all fixative for
|
||||
// various other ills. This is like opening up the hood and going in with a
|
||||
// wrench. To be used sparingly.
|
||||
std::string handleEdit ()
|
||||
int handleEdit (std::string &outs)
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
@@ -637,7 +643,8 @@ std::string handleEdit ()
|
||||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -666,6 +666,7 @@ static std::string importTask_1_6_0 (const std::vector <std::string>& lines)
|
||||
static std::string importTaskCmdLine (const std::vector <std::string>& lines)
|
||||
{
|
||||
std::vector <std::string> failed;
|
||||
std::string unused;
|
||||
|
||||
std::vector <std::string>::const_iterator it;
|
||||
for (it = lines.begin (); it != lines.end (); ++it)
|
||||
@@ -680,7 +681,7 @@ static std::string importTaskCmdLine (const std::vector <std::string>& lines)
|
||||
context.task.clear ();
|
||||
context.cmd.command = "";
|
||||
context.parse ();
|
||||
handleAdd ();
|
||||
(void)handleAdd (unused);
|
||||
context.clearMessages ();
|
||||
}
|
||||
|
||||
@@ -789,6 +790,8 @@ static std::string importTodoSh_2_0 (const std::vector <std::string>& lines)
|
||||
context.parse ();
|
||||
decorateTask (context.task);
|
||||
|
||||
context.task.set ("uuid", uuid ());
|
||||
|
||||
if (isPending)
|
||||
{
|
||||
context.task.setStatus (Task::pending);
|
||||
@@ -1144,7 +1147,7 @@ static std::string importCSV (const std::vector <std::string>& lines)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleImport ()
|
||||
int handleImport (std::string &outs)
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
@@ -1212,7 +1215,8 @@ std::string handleImport ()
|
||||
else
|
||||
throw std::string ("You must specify a file to import.");
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
71
src/main.h
71
src/main.h
@@ -55,25 +55,25 @@ int getDueState (const std::string&);
|
||||
bool nag (Task&);
|
||||
|
||||
// command.cpp
|
||||
std::string handleAdd ();
|
||||
std::string handleAppend ();
|
||||
std::string handleExport ();
|
||||
std::string handleDone ();
|
||||
std::string handleModify ();
|
||||
std::string handleProjects ();
|
||||
std::string handleCompletionProjects ();
|
||||
std::string handleTags ();
|
||||
std::string handleCompletionTags ();
|
||||
std::string handleCompletionCommands ();
|
||||
std::string handleCompletionIDs ();
|
||||
std::string handleCompletionConfig ();
|
||||
std::string handleVersion ();
|
||||
std::string handleDelete ();
|
||||
std::string handleStart ();
|
||||
std::string handleStop ();
|
||||
std::string handleColor ();
|
||||
std::string handleAnnotate ();
|
||||
std::string handleDuplicate ();
|
||||
int handleAdd (std::string &);
|
||||
int handleAppend (std::string &);
|
||||
int handleExport (std::string &);
|
||||
int handleDone (std::string &);
|
||||
int handleModify (std::string &);
|
||||
int handleProjects (std::string &);
|
||||
int handleCompletionProjects (std::string &);
|
||||
int handleTags (std::string &);
|
||||
int handleCompletionTags (std::string &);
|
||||
int handleCompletionCommands (std::string &);
|
||||
int handleCompletionIDs (std::string &);
|
||||
int handleCompletionConfig (std::string &);
|
||||
int handleVersion (std::string &);
|
||||
int handleDelete (std::string &);
|
||||
int handleStart (std::string &);
|
||||
int handleStop (std::string &);
|
||||
int handleColor (std::string &);
|
||||
int handleAnnotate (std::string &);
|
||||
int handleDuplicate (std::string &);
|
||||
void handleUndo ();
|
||||
#ifdef FEATURE_SHELL
|
||||
void handleShell ();
|
||||
@@ -85,27 +85,28 @@ int deltaAttributes (Task&);
|
||||
int deltaSubstitutions (Task&);
|
||||
|
||||
// edit.cpp
|
||||
std::string handleEdit ();
|
||||
int handleEdit (std::string &);
|
||||
|
||||
// report.cpp
|
||||
std::string shortUsage ();
|
||||
std::string longUsage ();
|
||||
std::string handleInfo ();
|
||||
std::string handleReportSummary ();
|
||||
std::string handleReportNext ();
|
||||
std::string handleReportHistory ();
|
||||
std::string handleReportGHistory ();
|
||||
std::string handleReportCalendar ();
|
||||
std::string handleReportStats ();
|
||||
std::string handleReportTimesheet ();
|
||||
int shortUsage (std::string &);
|
||||
int longUsage (std::string &);
|
||||
int handleInfo (std::string &);
|
||||
int handleReportSummary (std::string &);
|
||||
int handleReportNext (std::string &);
|
||||
int handleReportHistory (std::string &);
|
||||
int handleReportGHistory (std::string &);
|
||||
int handleReportCalendar (std::string &);
|
||||
int handleReportStats (std::string &);
|
||||
int handleReportTimesheet (std::string &);
|
||||
std::string getFullDescription (Task&);
|
||||
std::string getDueDate (Task&);
|
||||
|
||||
// custom.cpp
|
||||
std::string handleCustomReport (const std::string&);
|
||||
std::string runCustomReport (const std::string&, const std::string&,
|
||||
const std::string&, const std::string&,
|
||||
const std::string&, std::vector <Task>&);
|
||||
int handleCustomReport (const std::string&, std::string &);
|
||||
int runCustomReport (const std::string&, const std::string&,
|
||||
const std::string&, const std::string&,
|
||||
const std::string&, std::vector <Task>&,
|
||||
std::string&);
|
||||
void validReportColumns (const std::vector <std::string>&);
|
||||
void validSortColumns (const std::vector <std::string>&, const std::vector <std::string>&);
|
||||
|
||||
@@ -118,7 +119,7 @@ std::string colorizeFootnote (const std::string&);
|
||||
std::string colorizeDebug (const std::string&);
|
||||
|
||||
// import.cpp
|
||||
std::string handleImport ();
|
||||
int handleImport (std::string&);
|
||||
|
||||
// list template
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
extern Context context;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string shortUsage ()
|
||||
int shortUsage (std::string &outs)
|
||||
{
|
||||
Table table;
|
||||
|
||||
@@ -209,14 +209,19 @@ std::string shortUsage ()
|
||||
<< std::endl
|
||||
<< std::endl;
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string longUsage ()
|
||||
int longUsage (std::string &outs)
|
||||
{
|
||||
std::string shortUsageString;
|
||||
std::stringstream out;
|
||||
out << shortUsage ()
|
||||
|
||||
(void)shortUsage(shortUsageString);
|
||||
|
||||
out << shortUsageString
|
||||
<< "ID is the numeric identifier displayed by the 'task list' command. "
|
||||
<< "You can specify multiple IDs for task commands, and multiple tasks "
|
||||
<< "will be affected. To specify multiple IDs make sure you use one "
|
||||
@@ -276,13 +281,15 @@ std::string longUsage ()
|
||||
<< " $ ! ' \" ( ) ; \\ ` * ? { } [ ] < > | & % # ~" << "\n"
|
||||
<< std::endl;
|
||||
|
||||
return out.str ();
|
||||
outs = out.str();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Display all information for the given task.
|
||||
std::string handleInfo ()
|
||||
int handleInfo (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
// Get all the tasks.
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
@@ -497,18 +504,22 @@ std::string handleInfo ()
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
if (! tasks.size ())
|
||||
if (! tasks.size ()) {
|
||||
out << "No matches." << std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Project Remaining Avg Age Complete 0% 100%
|
||||
// A 12 13d 55% XXXXXXXXXXXXX-----------
|
||||
// B 109 3d 12h 10% XXX---------------------
|
||||
std::string handleReportSummary ()
|
||||
int handleReportSummary (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
// Scan the pending tasks.
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
@@ -648,10 +659,13 @@ std::string handleReportSummary ()
|
||||
<< table.rowCount ()
|
||||
<< (table.rowCount () == 1 ? " project" : " projects")
|
||||
<< std::endl;
|
||||
else
|
||||
else {
|
||||
out << "No projects." << std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -673,7 +687,7 @@ std::string handleReportSummary ()
|
||||
//
|
||||
// Make the "three" tasks a configurable number
|
||||
//
|
||||
std::string handleReportNext ()
|
||||
int handleReportNext (std::string &outs)
|
||||
{
|
||||
// Load report configuration.
|
||||
std::string columnList = context.config.get ("report.next.columns");
|
||||
@@ -718,7 +732,8 @@ std::string handleReportNext ()
|
||||
labelList,
|
||||
sortList,
|
||||
filterList,
|
||||
tasks);
|
||||
tasks,
|
||||
outs);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -744,8 +759,9 @@ time_t monthlyEpoch (const std::string& date)
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string handleReportHistory ()
|
||||
int handleReportHistory (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
std::map <time_t, int> groups; // Represents any month with data
|
||||
std::map <time_t, int> addedGroup; // Additions by month
|
||||
std::map <time_t, int> completedGroup; // Completions by month
|
||||
@@ -891,15 +907,19 @@ std::string handleReportHistory ()
|
||||
out << optionalBlankLine ()
|
||||
<< table.render ()
|
||||
<< std::endl;
|
||||
else
|
||||
else {
|
||||
out << "No tasks." << std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleReportGHistory ()
|
||||
int handleReportGHistory (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
std::map <time_t, int> groups; // Represents any month with data
|
||||
std::map <time_t, int> addedGroup; // Additions by month
|
||||
std::map <time_t, int> completedGroup; // Completions by month
|
||||
@@ -1087,14 +1107,17 @@ std::string handleReportGHistory ()
|
||||
else
|
||||
out << "Legend: + added, X completed, - deleted" << std::endl;
|
||||
}
|
||||
else
|
||||
else {
|
||||
out << "No tasks." << std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleReportTimesheet ()
|
||||
int handleReportTimesheet (std::string &outs)
|
||||
{
|
||||
// Scan the pending tasks.
|
||||
std::vector <Task> tasks;
|
||||
@@ -1264,7 +1287,8 @@ std::string handleReportTimesheet ()
|
||||
end -= 7 * 86400;
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -1432,7 +1456,7 @@ std::string renderMonths (
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleReportCalendar ()
|
||||
int handleReportCalendar (std::string &outs)
|
||||
{
|
||||
// Each month requires 28 text columns width. See how many will actually
|
||||
// fit. But if a preference is specified, and it fits, use it.
|
||||
@@ -1604,11 +1628,12 @@ std::string handleReportCalendar ()
|
||||
<< optionalBlankLine ()
|
||||
<< std::endl;
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleReportStats ()
|
||||
int handleReportStats (std::string &outs)
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
@@ -1836,7 +1861,8 @@ std::string handleReportStats ()
|
||||
<< table.render ()
|
||||
<< optionalBlankLine ();
|
||||
|
||||
return out.str ();
|
||||
outs = out.str ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
83
src/task.h
Normal file
83
src/task.h
Normal file
@@ -0,0 +1,83 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -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:\""\"", "Att::composeF4 encoded \"");
|
||||
t.is (a5.composeF4 (), "name:\"&dquot;\"", "Att::composeF4 encoded \"");
|
||||
a5.value ("\t\",[]:");
|
||||
t.is (a5.composeF4 (), "name:\"&tab;",&open;&close;:\"", "Att::composeF4 fully encoded \\t\",[]:");
|
||||
t.is (a5.composeF4 (), "name:\"&tab;&dquot;,&open;&close;:\"", "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:\""\"");
|
||||
a7.parse (n);
|
||||
t.is (a7.composeF4 (), "name:\""\"",
|
||||
t.is (a7.composeF4 (), "name:\"&dquot;\"",
|
||||
"Att::parse (name:\""\")");
|
||||
|
||||
n = Nibbler ("name:\"&tab;",&open;&close;:\"");
|
||||
a7.parse (n);
|
||||
t.is (a7.composeF4 (), "name:\"&tab;",&open;&close;:\"",
|
||||
t.is (a7.composeF4 (), "name:\"&tab;&dquot;,&open;&close;:\"",
|
||||
"Att::parse (name:\"&tab;",&open;&close;:\")");
|
||||
|
||||
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:\""value\"", "Att::composeF4 -> name:\""value\"");
|
||||
t.is (a7.composeF4 (), "name:\"&dquot;value\"", "Att::composeF4 -> name:\"&dquot;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"\"", "Att::composeF4 -> name:\"value"\"");
|
||||
t.is (a7.composeF4 (), "name:\"value&dquot;\"", "Att::composeF4 -> name:\"value&dquot;\"");
|
||||
|
||||
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"ue\"", "Att::composeF4 -> name:\"val"ue\"");
|
||||
t.is (a7.composeF4 (), "name:\"val&dquot;ue\"", "Att::composeF4 -> name:\"val&dquot;ue\"");
|
||||
|
||||
n = Nibbler ("name\"");
|
||||
good = true;
|
||||
|
||||
@@ -40,7 +40,7 @@ if (open my $fh, '>', 'basic.rc')
|
||||
|
||||
# Test the usage command.
|
||||
my $output = qx{../task rc:basic.rc};
|
||||
like ($output, qr/You must specify a command, or a task ID to modify/, 'missing command and ID');
|
||||
like ($output, qr/You must specify a command, or a task ID to modify/m, 'missing command and ID');
|
||||
|
||||
# Test the version command.
|
||||
$output = qx{../task rc:basic.rc version};
|
||||
|
||||
@@ -43,10 +43,10 @@ if (open my $fh, '>', 'before.rc')
|
||||
# Create some exampel data directly.
|
||||
if (open my $fh, '>', 'pending.data')
|
||||
{
|
||||
# 1230000000 = 12/22/2008
|
||||
# 1229947200 = 12/22/2008
|
||||
# 1240000000 = 4/17/2009
|
||||
print $fh <<EOF;
|
||||
[description:"foo" entry:"1230000000" start:"1230000000" status:"pending" uuid:"27097693-91c2-4cbe-ba89-ddcc87e5582c"]
|
||||
[description:"foo" entry:"1229947200" start:"1229947200" status:"pending" uuid:"27097693-91c2-4cbe-ba89-ddcc87e5582c"]
|
||||
[description:"bar" entry:"1240000000" start:"1240000000" status:"pending" uuid:"08f72d91-964c-424b-8fd5-556434648b6b"]
|
||||
EOF
|
||||
|
||||
|
||||
106
src/tests/bug.hasnt.t
Executable file
106
src/tests/bug.hasnt.t
Executable file
@@ -0,0 +1,106 @@
|
||||
#! /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;
|
||||
|
||||
65
src/tests/bug.range.t
Executable file
65
src/tests/bug.range.t
Executable file
@@ -0,0 +1,65 @@
|
||||
#! /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;
|
||||
|
||||
61
src/tests/bug.recur.t
Executable file
61
src/tests/bug.recur.t
Executable file
@@ -0,0 +1,61 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2009, Paul Beckingham.
|
||||
## All rights reserved.
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify it under
|
||||
## the terms of the GNU General Public License as published by the Free Software
|
||||
## Foundation; either version 2 of the License, or (at your option) any later
|
||||
## version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
## details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License along with
|
||||
## this program; if not, write to the
|
||||
##
|
||||
## Free Software Foundation, Inc.,
|
||||
## 51 Franklin Street, Fifth Floor,
|
||||
## Boston, MA
|
||||
## 02110-1301
|
||||
## USA
|
||||
##
|
||||
################################################################################
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 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;
|
||||
|
||||
62
src/tests/bug.start.extra.t
Executable file
62
src/tests/bug.start.extra.t
Executable file
@@ -0,0 +1,62 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2009, Paul Beckingham.
|
||||
## All rights reserved.
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify it under
|
||||
## the terms of the GNU General Public License as published by the Free Software
|
||||
## Foundation; either version 2 of the License, or (at your option) any later
|
||||
## version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
## details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License along with
|
||||
## this program; if not, write to the
|
||||
##
|
||||
## Free Software Foundation, Inc.,
|
||||
## 51 Franklin Street, Fifth Floor,
|
||||
## Boston, MA
|
||||
## 02110-1301
|
||||
## USA
|
||||
##
|
||||
################################################################################
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 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;
|
||||
|
||||
@@ -42,7 +42,7 @@ if (open my $fh, '>', 'custom.rc')
|
||||
ok (-r 'custom.rc', 'Created custom.rc');
|
||||
}
|
||||
|
||||
# Generate the usage screen, and locate the custom report on it.
|
||||
# Add a recurring and non-recurring task, look for the indicator.
|
||||
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};
|
||||
|
||||
62
src/tests/feature.exit.t
Executable file
62
src/tests/feature.exit.t
Executable file
@@ -0,0 +1,62 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2009, Paul Beckingham.
|
||||
## All rights reserved.
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify it under
|
||||
## the terms of the GNU General Public License as published by the Free Software
|
||||
## Foundation; either version 2 of the License, or (at your option) any later
|
||||
## version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
## details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License along with
|
||||
## this program; if not, write to the
|
||||
##
|
||||
## Free Software Foundation, Inc.,
|
||||
## 51 Franklin Street, Fifth Floor,
|
||||
## Boston, MA
|
||||
## 02110-1301
|
||||
## USA
|
||||
##
|
||||
################################################################################
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 7;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'exit.rc')
|
||||
{
|
||||
print $fh "data.location=.\n",
|
||||
"confirmation=no\n";
|
||||
close $fh;
|
||||
ok (-r 'exit.rc', 'Created exit.rc');
|
||||
}
|
||||
|
||||
qx{../task rc:exit.rc add foo};
|
||||
my $exit_good = system ('../task rc:exit.rc ls foo 2>&1 >>/dev/null');
|
||||
is ($exit_good, 0, 'task returns 0 on success');
|
||||
my $exit_bad = system ('../task rc:exit.rc ls bar 2>&1 >>/dev/null');
|
||||
isnt ($exit_bad, 0, 'task returns non-zero on failure');
|
||||
|
||||
# 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 'exit.rc';
|
||||
ok (!-r 'exit.rc', 'Removed exit.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
@@ -111,52 +111,25 @@ unlike ($output, qr/six/, 'g6');
|
||||
unlike ($output, qr/seven/, 'g7');
|
||||
|
||||
$output = qx{../task rc:filter.rc list -tag};
|
||||
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');
|
||||
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');
|
||||
|
||||
$output = qx{../task rc:filter.rc list -missing};
|
||||
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');
|
||||
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');
|
||||
|
||||
$output = qx{../task rc:filter.rc list +tag -tag};
|
||||
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/one/, 'j1');
|
||||
unlike ($output, qr/two/, 'j2');
|
||||
unlike ($output, qr/three/, 'j3');
|
||||
unlike ($output, qr/four/, 'j4');
|
||||
@@ -164,25 +137,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 +tag};
|
||||
$output = qx{../task rc:filter.rc list project:A priority:H};
|
||||
like ($output, qr/one/, 'k1');
|
||||
unlike ($output, qr/two/, 'k2');
|
||||
like ($output, qr/two/, 'k2');
|
||||
unlike ($output, qr/three/, 'k3');
|
||||
unlike ($output, qr/four/, 'k4');
|
||||
unlike ($output, qr/five/, 'k5');
|
||||
unlike ($output, qr/six/, 'k6');
|
||||
unlike ($output, qr/seven/, 'k7');
|
||||
|
||||
$output = qx{../task rc:filter.rc list project:A priority:H foo};
|
||||
like ($output, qr/one/, 'l1');
|
||||
$output = qx{../task rc:filter.rc list project:A priority:};
|
||||
unlike ($output, qr/one/, 'l1');
|
||||
unlike ($output, qr/two/, 'l2');
|
||||
unlike ($output, qr/three/, 'l3');
|
||||
like ($output, qr/three/, 'l3');
|
||||
unlike ($output, qr/four/, 'l4');
|
||||
unlike ($output, qr/five/, 'l5');
|
||||
unlike ($output, qr/six/, 'l6');
|
||||
unlike ($output, qr/seven/, 'l7');
|
||||
|
||||
$output = qx{../task rc:filter.rc list project:A priority:H +tag};
|
||||
$output = qx{../task rc:filter.rc list project:A foo};
|
||||
like ($output, qr/one/, 'm1');
|
||||
unlike ($output, qr/two/, 'm2');
|
||||
unlike ($output, qr/three/, 'm3');
|
||||
@@ -191,7 +164,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 priority:H foo +tag};
|
||||
$output = qx{../task rc:filter.rc list project:A +tag};
|
||||
like ($output, qr/one/, 'n1');
|
||||
unlike ($output, qr/two/, 'n2');
|
||||
unlike ($output, qr/three/, 'n3');
|
||||
@@ -200,14 +173,41 @@ 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/, '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');
|
||||
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');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
|
||||
Reference in New Issue
Block a user