Merge branch '1.8.0'

Conflicts:
	.gitignore
	AUTHORS
	ChangeLog
	DEVELOPERS
	Makefile.am
	NEWS
	README
	configure.ac
	doc/man/task.1
	doc/man/taskrc.5
	src/T.cpp
	src/T.h
	src/TDB.cpp
	src/TDB.h
	src/command.cpp
	src/edit.cpp
	src/import.cpp
	src/parse.cpp
	src/report.cpp
	src/rules.cpp
	src/task.cpp
	src/task.h
	task_completion.sh
This commit is contained in:
Paul Beckingham 2009-07-21 19:15:54 -04:00
commit 90d53245c3
231 changed files with 16844 additions and 11820 deletions

7
.gitignore vendored
View file

@ -5,11 +5,14 @@ config.h.in
config.status config.status
src/.deps src/.deps
src/Makefile src/Makefile
*/task */*task
stamp-h1 stamp-h1
Makefile Makefile
Makefile.in
configure configure
config.log config.log
www.xls www.xls
src/tests/all.log
src/tests/*.data
*~ *~
Makefile.in .*.swp

15
AUTHORS
View file

@ -1,7 +1,10 @@
Principal Author: The development of task was made possible by the significant contributions of the following people:
Paul Beckingham Paul Beckingham (Principal Author)
Federico Hernandez (Package Maintainer & Contributing Author)
David J Patrick (Designer)
John Florian (Contributing Author)
Contributing Authors: The following submitted code, packages or analysis, and deserve special thanks:
Damian Glenny Damian Glenny
Andy Lester Andy Lester
H. İbrahim Güngör H. İbrahim Güngör
@ -10,14 +13,12 @@ Contributing Authors:
Benjamin Tegarden Benjamin Tegarden
Chris Pride Chris Pride
Richard Querin Richard Querin
Federico Hernandez
T. Charles Yun T. Charles Yun
David J Patrick
P.C. Shyamshankar P.C. Shyamshankar
Johan Friis Johan Friis
Steven de Brouwer Steven de Brouwer
With thanks to: Thanks to the following, who submitted detailed bug reports and excellent suggestions:
Eugene Kramer Eugene Kramer
Srijith K Srijith K
Bruce Israel Bruce Israel
@ -34,4 +35,6 @@ With thanks to:
Bruce Dillahunty Bruce Dillahunty
Askme Too Askme Too
Mike Adonay Mike Adonay
Thomas@BIC
Ian Mortimer

View file

@ -1,14 +1,83 @@
------ current release --------------------------- ------ current release ---------------------------
1.8.0 (7/21/2009)
+ Added zsh tab completion script (thanks to P.C. Shyamshankar).
+ Fixed bug that cause the _forcecolor configuration variable to be
considered obsolete (thank to Bruce Dillahunty).
+ Fixed documentation errors (thanks to Thomas@BIC).
+ The 'weekstart' configuration variable now controls the 'calendar'
report (thanks to Federico Hernandez).
+ The 'displayweeknumber' configuration variable now controls the display
of week number in the 'calendar' report (thanks to Federico Hernandez).
+ Supports '--' argument to indicate that all subsequence arguments are
part of the description, despite what they otherwise might mean.
+ Removed support for the obsolete task file format 1 (never released).
+ Fixed bug that allowed blank annotations to be added (thanks to Bruce
Dillahunty).
+ Supports negative tag filters, so that (task list +foo -bar) now filters
tasks that have the "foo" tag, but do not have the "bar" tag (thanks to
Chris Pride).
+ Custom reports now support a more compact form of the "age" column,
called "age_compact" (thanks to T. Charles Yun).
+ Supports 'rc.name:value' for a command line override to .taskrc data
(thanks to Federico Hernandez).
+ Removed obsolete DEVELOPERS file. The online support forums at
http://taskwarrior.org will provide better information.
+ Fixed bug that kept some deleted tasks showing up on the calendar report
(thanks to Federico Hernandez).
+ Now asks the user to confirm large changes if configuration variable
'confirmation' is set to 'yes'. A large change is one that completely
replaces a task description, or operates on a large number of tasks,
which defaults to 4 but is configurable via the 'bulk' configuration
variable (thanks to John Florian).
+ Now echoes back the new task ID on 'add' (thanks to Bruce Dillahunty).
+ The new "shell" command provides an interactive shell for task. All
commands are supported (thanks to Bruce Dillahunty, Federico Hernandez,
and John Florian).
+ New "recurring" report to list all recurring tasks.
+ New, more flexible, more consistent, grep-able file format.
+ If task is renamed to "cal", or there is a symlink to task called "cal",
then task can act as a replacement for the Unix "cal" command.
+ Supports arguments to the cal command like "month year", "year", etc.
+ The "tags" report now shows the tag usage count.
+ The "projects" report now shows totals by project and priority.
+ Now supports attribute modifiers that allow much finer control over report
filtering, for example "task list due.before:friday", or "task list
pri.not:H" and many more.
+ Now supports new "age_compact" and "wait" custom report columns.
+ Now supports colorization of the header and footnote messages that are
printed before and after report output, with the 'color.header' and
'color.footnote' configuration variables.
+ Now supports the 'limit' attribute, to control the number of tasks that
are shown, for example: "task list limit:10".
+ Now supports a debug mode that can be used to generate helpful information
when reporting a problem. Just run the command with "task rc.debug:on ..."
and diagnostics will be generated that will help pinpoint a problem.
+ The new "undo" command replaces the old "undo" and "undelete" command
with a complete undo stack that can rollback all changes.
+ While waiting for a file lock, task states the reason for the delay.
+ Now supports a 'waiting' state that causes tasks to not appear until
a certain date, for example "task <ID> wait:<date>". The task
will then not show up on any report (except 'all') until that date.
+ The "active", "completed", "overdue" and "next" reports are now custom
reports, and therefore modifiable.
+ Now supports a 'waiting' custom report to list all waiting tasks.
+ Now supports a 'recurring' custom report to list all recurring tasks.
+ Now supports an 'all' report to list all tasks, including deleted
+ Supports command aliases - create an alias for any command by creating
a .taskrc entry like "alias.new_name=old_name".
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)
+ Fixed build failure on OpenBSD (thanks to Mike Adonay). + Fixed build failure on OpenBSD (thanks to Mike Adonay).
+ Took the opportunity of a patch release to update the various email + Took the opportunity of a patch release to update the various email
addresses and URLs in the various documents. addresses and URLs in the various documents.
------ old releases ------------------------------ 1.7.0 (5/14/2009) f6b8b39d8b4a85c30a457e9e78b582b74531bfe4
1.7.0 (5/14/2009)
+ Improved the errors when parsing a corrupt or unrecognized pending.data + Improved the errors when parsing a corrupt or unrecognized pending.data
or completed.data file (thanks to T. Charles Yun). or completed.data file (thanks to T. Charles Yun).
+ Added details to the "info" report about recurring tasks (thanks to T. + Added details to the "info" report about recurring tasks (thanks to T.
@ -38,8 +107,8 @@
to /usr/local/share/task (thanks to Federico Hernandez). to /usr/local/share/task (thanks to Federico Hernandez).
+ Applied patch to allow task to build on Arch Linux (thanks to Johan Friis). + Applied patch to allow task to build on Arch Linux (thanks to Johan Friis).
+ Applied patch to fix a UUID bug on Solaris 8 (thanks to Steven de Brouwer). + Applied patch to fix a UUID bug on Solaris 8 (thanks to Steven de Brouwer).
+ The task man page is now installed. Try "man task" (thanks to Federico + The task and taskrc man pages are here. Try "man task", "man taskrc"
Hernandez and P.C. Shyamshankar). (thanks to Federico Hernandez and P.C. Shyamshankar).
+ Fixed bug that causes task to create a default .task directory, even if + Fixed bug that causes task to create a default .task directory, even if
data.location specified otherwise (thanks to Federico Hernandez). data.location specified otherwise (thanks to Federico Hernandez).
+ New "edit" command that fires up a text editor (uses 'editor' configuration + New "edit" command that fires up a text editor (uses 'editor' configuration
@ -287,7 +356,7 @@
+ Made unit tests compile and run again. + Made unit tests compile and run again.
+ Removed tests from distibution. + Removed tests from distibution.
0.9.6 (5/13/208) 0.9.6 (5/13/2008)
+ Corrected wrong include file in Table.cpp. + Corrected wrong include file in Table.cpp.
+ Replaced color management code. + Replaced color management code.
+ Improved color rules code. + Improved color rules code.
@ -334,7 +403,7 @@
+ Rules-based colorization. + Rules-based colorization.
0.8.1 (1/28/2008) - 0.8.16 (3/13/2008) 0.8.1 (1/28/2008) - 0.8.16 (3/13/2008)
+ autoconf conversion (many builds). + autoconf conversion
0.8.0 Polish (1/25/2008) 0.8.0 Polish (1/25/2008)
+ Code cleanup, reorganization. + Code cleanup, reorganization.

View file

@ -1,22 +0,0 @@
Developers may wish to change task, and here is a high-level guide to the files
included.
task.{cpp,h} Implements main, high level processing.
command.cpp Implements all non-report task commands.
report.cpp Implements all task reports.
parse.cpp Parses the command line.
TDB.{cpp,h} The task database, performs all file I/O.
T.{cpp,h} Represents a single task - parses a record from TDB, and also
composes record for TDB. Provides accessors for tasks.
Grid.{cpp,h} Implements a sparse 2D array, provides data storage for the
Table object.
Table.{cpp,h} Implements tabular data rendering, wrapping etc.
Config.{cpp,h} Implements a reader for the .taskrc file.
Date.{cpp,h} General date class for the time_t type.
text.cpp Text manipulation functions.
util.cpp General utility functions.
color.cpp Color support functions.
rules.cpp Auto-colorization rules.
Please send bugs, patches to support@taskwarrior.org

View file

@ -1,6 +1,20 @@
SUBDIRS = src SUBDIRS = src
EXTRA_DIST = task_completion.sh doc/man1/task.1 doc/man5/taskrc.5
man1_MANS = doc/man1/task.1 dist_man_MANS = doc/man/task.1 doc/man/taskrc.5 doc/man/task-tutorial.5
man5_MANS = doc/man5/taskrc.5
otherdir = $(datadir)/doc/task-$(VERSION) docdir = $(datadir)/doc/${PACKAGE}-${VERSION}
other_DATA = AUTHORS ChangeLog COPYING INSTALL NEWS README task_completion.sh doc_DATA = AUTHORS ChangeLog COPYING NEWS README
EXTRA_DIST = INSTALL
bashscriptsdir = $(docdir)
nobase_dist_bashscripts_DATA = scripts/bash/task_completion.sh
zshscriptsdir = $(docdir)
nobase_dist_zshscripts_DATA = scripts/zsh/_task
vimscriptsdir = $(docdir)
nobase_dist_vimscripts_DATA = scripts/vim/README scripts/vim/ftdetect/task.vim scripts/vim/syntax/taskdata.vim scripts/vim/syntax/taskedit.vim
i18ndir = $(docdir)
nobase_dist_i18n_DATA = i18n/strings.de-DE i18n/strings.en-US i18n/strings.es-ES i18n/strings.fr-FR i18n/strings.nl-NL i18n/strings.sv-SE i18n/tips.de-DE i18n/tips.en-US i18n/tips.sv-SE

55
NEWS
View file

@ -1,43 +1,48 @@
Welcome to Task 1.7.1.
New Features in task 1.8.0
- Attribute modifiers, for precise queries
- Improved calendar feature
- Full undo capability
- All reports now customizable
- Command aliases can now be created
- 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
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: Task has been built and tested on the following configurations:
- OS X 10.4 Tiger
- OS X 10.5 Leopard - OS X 10.5 Leopard
- Fedora Core 8 - OS X 10.4 Tiger
- Fedora Core 9 - Fedora Core 11 Leonidas
- Fedora Core 10 - Fedora Core 10 Cambridge
- Ubuntu 7 Feisty Fawn
- Ubuntu 8 Hardy Heron
- Ubuntu 8.10 Intrepid Ibex
- Ubuntu 9.04 Jaunty Jackalope - Ubuntu 9.04 Jaunty Jackalope
- Ubuntu 8.10 Intrepid Ibex
- Ubuntu 8.04 Hardy Heron
- Slackware 12.2
- Arch Linux - Arch Linux
- OpenBSD 4.5
- Solaris 8
- Solaris 10 - Solaris 10
- Solaris 8
- OpenBSD 4.5
- FreeBSD
- Cygwin 1.5.25-14 - Cygwin 1.5.25-14
While Task has undergone testing, bugs are sure to remain. If you encounter a While Task has undergone testing, bugs are sure to remain. If you encounter a
bug, please contact me at support@taskwarrior.org. Here is what you could do, in bug, please enter a new issue at:
order of increasing effort (to you) and usefulness (to me):
- Do nothing. Bug probably won't get fixed. http://taskwarrior.org/projects/taskwarrior/issues/new
- Send an email to support@taskwarrior.org, explaining what you saw. The bug Or you can also report the issue in the forums at:
will be addressed, and a new release will be made. You will be a hero.
- Send an email, and a reproducible test case in the form of the few commands http://taskwarrior.org/projects/taskwarrior/boards
it takes to recreate the problem. The bug will be addressed, and a new
release will be made. You will be a hero.
- If you are a developer, send a patch that fixes the problem. Your patch Or just send a message to:
will be applied and tested, and a new release will be made. You will be a
hero.
- Another option involves using the taskwarrior.org issue tracker, which can support@taskwarrior.org
be found at http://taskwarrior.org/projects/taskwarrior/issues/new which has
the advantage that everyone gets to see and track the issue. You will still
be a hero.
Thank you. Thank you.
---

61
README
View file

@ -1,51 +1,24 @@
Thank you for taking a look at task. Task is a GTD utility featuring:
- Robust C++ implementation Thank you for taking a look at task!
- Tags
- Colorful, tabular output
- Reports, graphs
- Lots of commands
- Low-level API
- Abbreviations for all commands, options
- Multi-user file locking
- Clean architecture allowing quick addition of new features
- Recurring tasks
It is intended that features, mainly in the form of reports will be added Task is a GTD, todo list, task management, command line utility with a multitude
frequently, with best practices and useful reports evolving from usage patterns. of features. It is a portable, well supported, very active project, and it is
Open Source. Task has binary distributions, online documentation, demonstration
Task is scope-limited to GTD-like functionality only. movies, and you'll find all the details at the site:
You may want to watch the old task movie on YouTube:
http://www.youtube.com/watch?v=l68LCl6BYvs
or the new improved one:
http://www.youtube.com/watch?v=D2Kn4DMOVSw
Either will give you a fairly good idea of what task is capable of, and
whether it fits in to your way of working. As a command line application,
task is not for everyone and some of you may prefer to not proceed. The
movie or online tutorial file are the quickest way for you to make that
decision. The online tutorial can be found at:
http://taskwarrior.org/wiki/taskwarrior/Simple
Task has many more features than todo.sh, but fundamentally, they are
both working toward the same goals, which is to help you follow basic
Getting Things Done (GTD) principles.
All feedback is welcome, in addition to any bug reports or patches to:
support@taskwarrior.org
Or better yet, get involved in the discussion at
http://taskwarrior.org http://taskwarrior.org
Got an idea for an enhancement? Post a message! At the site you'll find a wiki, discussion forums, downloads, news and more.
We have found that task makes me more productive and organized.
We hope task can do the same for you.
Your contributions are especially welcome. Whether it comes in the form of
code patches, ideas, discussion, bug reports or just encouragement, your input
is needed.
Please send your support questions and code patches to:
support@taskwarrior.org
Consider joining taskwarrior.org and participating in the future of task.
---

View file

@ -1,51 +0,0 @@
Thank you for taking a look at task. Task is a GTD utility featuring:
- Robust C++ implementation
- Tags
- Colorful, tabular output
- Reports, graphs
- Lots of commands
- Low-level API
- Abbreviations for all commands, options
- Multi-user file locking
- Clean architecture allowing quick addition of new features
- Recurring tasks
It is intended that features, mainly in the form of reports will be added
frequently, with best practices and useful reports evolving from usage patterns.
Task is scope-limited to GTD functionality only.
You may want to watch the old task movie on YouTube:
http://www.youtube.com/watch?v=l68LCl6BYvs
or the new improved one:
http://www.youtube.com/watch?v=D2Kn4DMOVSw
Either will give you a fairly good idea of what task is capable of, and
whether it fits in to your way of working. As a command line application,
task is not for everyone and some of you may prefer to not proceed. The
movie or online tutorial file are the quickest way for you to make that
decision. The online tutorial can be found at:
http://www.beckingham.net/task.html
Task is based on ideas presented in the todo.sh script, found on:
http://todotxt.org
Task has many more features than todo.sh, but fundamentally, they are
both working toward the same goals, which is to help you follow basic
Getting Things Done (GTD) principles.
All feedback is welcome, in addition to any bug reports or patches to:
task@beckingham.net
Got an idea for an enhancement? Send a message!
I have found that task makes me more productive and organized.
I hope task can do the same for you.

View file

@ -1,44 +0,0 @@
Adding New Command Checklist
----------------------------
- Create new handler in command.cpp or report.cpp.
- Add prototype to task.h.
- Add call to appropriate section in task.cpp.
- Add usage info in task.cpp.
- Add command name to list in parse.cpp.
- Add unit tests in src/tests.
- Add new configuration details to html/config.html.
- Add command details to html/advanced.html.
- Add description to ChangeLog, with attribution if the idea
came from a single user, but not if it came from multiple
users.
- Add description to html/task.html.
Release Checklist
-----------------
- Update "Upcoming Features" document on group
- Ensure all unit tests pass on OS X
- Ensure clean build on OS X
- Make a source package (1)
- Ensure clean build on latest Fedora Core from source package
- Git clone and rebuild, ensure all unit tests pass
- Ensure clean build on latest Ubuntu from source package
- Git clone and rebuild, ensure all unit tests pass
- Ensure clean build on Windows/Cygwin from source package
- Git clone and rebuild, ensure all unit tests pass
- Make a new source package (2)
- Add actual release date to ChangeLog
- Add actual release date to html/task.html
- Merge version branch to master
- Tag master
- Make a new source package (3)
- Send source package to package maintainer
- Make OS X .pkg package
- Wait for all packages
- Upload all packages to website
- Upload all docs to website
- Send announcement to group

View file

@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script. # Process this file with autoconf to produce a configure script.
AC_PREREQ(2.61) AC_PREREQ(2.61)
AC_INIT(task, 1.7.1, support@taskwarrior.org) AC_INIT(task, 1.8.0, support@taskwarrior.org)
CFLAGS="${CFLAGS=}" CFLAGS="${CFLAGS=}"
CXXFLAGS="${CXXFLAGS=}" CXXFLAGS="${CXXFLAGS=}"
@ -10,7 +10,7 @@ CXXFLAGS="${CXXFLAGS=}"
# to the configure script (./configure --enable-debug) # to the configure script (./configure --enable-debug)
# Check if we have enable debug support. # Check if we have enable debug support.
AC_MSG_CHECKING(whether to enable debugging) AC_MSG_CHECKING(whether to enable debugging)
debug_default="yes" debug_default="no"
AC_ARG_ENABLE(debug, [ --enable-debug=[no/yes] turn on debugging AC_ARG_ENABLE(debug, [ --enable-debug=[no/yes] turn on debugging
[default=$debug_default]],, enable_debug=$debug_default) [default=$debug_default]],, enable_debug=$debug_default)
# Yes, shell scripts can be used # Yes, shell scripts can be used
@ -33,7 +33,7 @@ else
fi fi
AM_INIT_AUTOMAKE AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([src/task.cpp]) AC_CONFIG_SRCDIR([src/main.cpp])
AC_CONFIG_HEADER([auto.h]) AC_CONFIG_HEADER([auto.h])
# Checks for programs. # Checks for programs.

394
doc/man/task-tutorial.5 Normal file
View file

@ -0,0 +1,394 @@
.TH task-tutorial 5 2009-07-14 "Task 1.8.0" "User Manuals"
.SH NAME
task-tutorial \- A tutorial for the task(1) command line todo manager.
.SH DESCRIPTION
Task is a command line TODO list manager. It maintains a list of tasks that you
want to do, allowing you to add/remove, and otherwise manipulate them. Task
has a rich list of subcommands that allow you to do various things with it.
.SH 30 second tutorial
For the excessively lazy. Add two tasks:
.br
.RS
$ task add Read task documents later
.br
$ task add priority:H Pay bills
.RE
Easy. See that second one has a High priority? Now let's look at those tasks:
.br
.RS
$ task ls
.br
ID Project Pri Description
.br
2 H Pay bills
.br
1 Read task documents later
.RE
They are ordered by priority. Let's mark number 2 as done:
.br
.RS
$ task 2 done
.br
$ task ls
.br
ID Project Pri Description
.br
1 Read task documents later
.RE
Gone. Now let's delete that remaining task, because, well, why bother
now we are already using task:
.br
.RS
$ task delete 1
.br
$ task ls
.br
No matches
.RE
Easy. But now consider checking out what task can really do...
.SH Simple usage of task
Let us begin by adding some tasks:
.br
.RS
$ task add Book plane ticket
.br
$ task add Rent a tux
.br
$ task add Reserve a rental car
.br
$ task add Reserve a hotel room
.RE
That's it. You'll notice immediately that task has a very minimalist
interface. Let us take a look at those tasks:
.br
.RS
$ task ls
.br
ID Project Pri Description
.br
1 Book plane ticket
.br
2 Rent a tux
.br
3 Reserve a rental car
.br
4 Send John a birthday card
.RE
The 'ls' command provides the most minimal list of tasks. Each task has
been given an id number, and you can see that there are no projects or
priorities assigned. Wait a minute - I own a tux, I don't need to rent
one. Let us delete task 2:
.br
.RS
$ task 2 delete
.br
Permanently delete task? (y/n) y
.RE
Task wants you to confirm deletions. To remove the confirmation, edit
your .taskrc file and change the line:
.br
.RS
confirmation=yes
.RE
.br
to have a value of "no".
While the use of projects and priorities are not essential to benefiting
from task, they can be very useful when the list of tasks grows large.
Let's assign a project to these tasks:
.br
.RS
$ task 1 project:Wedding
.br
$ task 3 project:Wedding
.br
$ task 4 project:Family
.br
$ task ls
.br
ID Project Pri Description
.br
3 Family Send John a birthday card
.br
2 Wedding Reserve a rental car
.br
1 Wedding Book plane ticket
.RE
Notice that the id numbers have changed. When tasks get deleted, or have
their attributes changed (project, for example), the ids are prone to change.
But the id numbers will remain valid until the next 'ls' command is run.
You should only use the ids from the most recent 'ls' command. The ids change,
because task is always trying to use small numbers so that it is easy for you
to enter them correctly. Now that projects are assigned, we can look at just
the Wedding project tasks:
Subprojects are supported. If you have a project "Wedding", you can specify
that a task is a subproject "Transport" of "Wedding" by assigning the project
"Wedding.Transport". Let's do this:
.br
.RS
$ task 2 project:Wedding.Transport
.br
$ task ls
.br
ID Project Pri Description
.br
3 Family Send John a birthday card
.br
2 Wedding.Transport Reserve a rental car
.br
1 Wedding Book plane ticket
.RE
Task matches the leftmost part of the project when searching, so projects may
be abbreviated:
.br
.RS
$ task ls project:Wedding.Tra
.br
ID Project Pri Description
.br
2 Wedding.Transport Reserve a rental car
.RE
This way of matching projects can be used to see all tasks under the "Wedding"
project and all subprojects:
.br
.RS
$ task ls project:Wedding
.br
ID Project Pri Description
.br
2 Wedding.Transport Reserve a rental car
.br
1 Wedding Book plane ticket
.RE
Let's reassign 2 back to the "Wedding" project:
.br
.RS
$ task 2 project:Wedding
.RE
Now that projects are assigned, we can look at just the Wedding project tasks:
.br
.RS
$ task ls project:Wedding
.br
ID Project Pri Description
.br
1 Wedding Book plane ticket
.br
2 Wedding Reserve a rental car
.RE
Any command arguments after the 'ls' are used for filtering the output.
We could also have requested:
.br
.RS
$ task ls ticket plane
.br
ID Project Pri Description
.br
1 Wedding Book plane ticket
.RE
Now let's prioritize. Priorities can be H, M or L (High, Medium, Low).
.br
.RS
$ task ls
.br
ID Project Pri Description
.br
3 Family Send John a birthday card
.br
2 Wedding Reserve a rental car
.br
1 Wedding Book plane ticket
.br
$ task 1 priority:H
.br
$ task 2 prior:M
.br
$ task 3 pr:H
.br
Ambiguous attribute 'pr' - could be either of project, priority
.br
$ task 3 pri:H
.br
$ task ls
.br
ID Project Pri Description
.br
3 Family H Send John a birthday card
.br
1 Wedding H Book plane ticket
.br
2 Wedding M Reserve a rental car
.RE
Notice that task supports the abbreviation of words such as priority,
project. Priority can be abbreviated to pri, but not pr, because it
is ambiguous. Now that tasks have been prioritized, you can see that
the tasks are being sorted by priority, with the highest priority
tasks at the top.
These attributes can all be provided when the task is added, instead of
applying them afterwards, as shown. The following command shows how to
set all the attributes at once:
.br
.RS
$ task add project:Wedding priority:H Book plane ticket
.RE
The 'ls' command provides the least information for each task. The 'list'
command provides more:
.br
.RS
$ task list
.br
ID Project Pri Due Active Age Description
.br
3 Family H 4 mins Send John a birthday card
.br
1 Wedding H 5 mins Book plane ticket
.br
2 Wedding M 5 mins Reserve a rental car
.RE
Notice that a task can have a due date, and can be active. The task lists are
sorted by due date, then priority. Let's add due dates:
.br
.RS
$ task 3 due:6/25/2008
.br
$ task 1 due:7/31/2008
.br
$ task list
.br
ID Project Pri Due Active Age Description
.br
3 Family H 6/25/2008 6 mins Send John a birthday card
.br
1 Wedding H 7/31/2008 7 mins Book plane ticket
.br
2 Wedding M 7 mins Reserve a rental car
.RE
If today's date is 6/23/2008, then task 3 is due in 2 days. It will be colored
yellow if your terminal supports color. To change this color, edit your .taskrc
file, and change the line to one of these alternatives:
.br
.RS
color.due=red
.br
color.due=on_blue
.br
color.due=red on_blue
.br
color.due=bold_red on_blue
.RE
Where color is one of the following:
.br
.RS
black, blue, red, green, cyan, magenta, yellow or white
.RE
All colors are specified in this way. Take a look in .taskrc for all the other
color rules that you control.
Tagging tasks is a good way to group them, aside from specifying a project.
To add a tag to a task:
.br
.RS
$ task <id> +tag
.RE
The plus sign indicates that this is a tag. Any number of tags may be applied to a
task, and then used for searching. Tags are just single words that are labels.
.br
.RS
$ task list
.br
ID Project Pri Due Active Age Description
.br
3 Family H 6/25/2008 8 mins Send John a birthday card
.br
1 Wedding H 7/31/2008 9 mins Book plane ticket
.br
2 Wedding M 9 mins Reserve a rental car
.br
$ task 1 +phone
.br
$ task 2 +phone
.br
$ task 3 +shopping
.br
$ task 3 +john
.br
$ task list +phone
.br
ID Project Pri Due Active Age Description
.br
1 Wedding H 7/31/2008 9 mins Book plane ticket
.br
2 Wedding M 9 mins Reserve a rental car
.RE
To remove a tag from a task, use the minus sign:
.br
.RS
$ task 3 \-john
.RE
.SH Advanced usage of task
Advanced examples of the usage of task can be found at
the official site at <http://taskwarrior.org>
.SH "CREDITS & COPYRIGHTS"
task was written by P. Beckingham <paul@beckingham.net>.
.br
Copyright (C) 2006 \- 2009 P. Beckingham
This man page was originally written by Federico Hernandez.
task is distributed under the GNU General Public License. See
http://www.gnu.org/licenses/gpl-2.0.txt for more information.
.SH SEE ALSO
.BR task(1),
.BR taskrc(5)
For more information regarding task, the following may be referenced:
.TP
The official site at
<http://taskwarrior.org>
.TP
The official code repository at
<http://github.com/pbeckingham/task/>
.TP
You can contact the project by writing an email to
<support@taskwarrior.org>
.SH REPORTING BUGS
.TP
Bugs in task may be reported to the issue-tracker at
<http://taskwarrior.org>

View file

@ -1,4 +1,4 @@
.TH task 1 2009-05-14 "Task 1.7.1" "User Manuals" .TH task 1 2009-07-14 "Task 1.8.0" "User Manuals"
.SH NAME .SH NAME
task \- A command line todo manager. task \- A command line todo manager.
@ -7,7 +7,7 @@ task \- A command line todo manager.
.B task [subcommand] [args] .B task [subcommand] [args]
.SH DESCRIPTION .SH DESCRIPTION
Task is a command line TODO list manager. It maintains a list of tasks that you Task is a command line todo list manager. It maintains a list of tasks that you
want to do, allowing you to add/remove, and otherwise manipulate them. Task want to do, allowing you to add/remove, and otherwise manipulate them. Task
has a rich list of subcommands that allow you to do various things with it. has a rich list of subcommands that allow you to do various things with it.
@ -26,22 +26,30 @@ task.
.B annotate ID description .B annotate ID description
Adds an annotation to an existing task. Adds an annotation to an existing task.
.TP
.B completed [tags] [attrs] description
Provides a chronological listing of all completed tasks matching specified
criteria.
.TP .TP
.B ID [tags] [attrs] [description] .B ID [tags] [attrs] [description]
Modifies the existing task with provided information. Modifies the existing task with provided information.
.TP .TP
.B ID /from/to/ .B ID /from/to/
Performs one substitution on task description for fixing mistakes. Performs one substitution on task description and annotation for fixing mistakes.
.TP .TP
.B ID /from/to/g .B ID /from/to/g
Performs all substitutions on task description for fixing mistakes. Performs all substitutions on task description and annotation for fixing mistakes.
.TP
.B edit ID
Launches an editor to let you modify all aspects of a task directly.
Use carefully.
.TP
.B undo
Reverts the most recent action.
.TP
.B shell
Launches an interactive shell with all the task commands available.
.TP .TP
.B duplicate ID [tags] [attrs] [description] .B duplicate ID [tags] [attrs] [description]
@ -51,10 +59,6 @@ Duplicates the specified task and allows modifications.
.B delete ID .B delete ID
Deletes the specified task from task list. Deletes the specified task from task list.
.TP
.B undelete ID
Undeletes the specified task, provided a report has not yet been run.
.TP .TP
.B info ID .B info ID
Shows all data and metadata for the specified task. Shows all data and metadata for the specified task.
@ -73,10 +77,6 @@ time from the specified task.
.B done ID [tags] [attrs] [description] .B done ID [tags] [attrs] [description]
Marks the specified task as done. Marks the specified task as done.
.TP
.B undo ID
Marks the specified task as pending, provided a report has not yet been run.
.TP .TP
.B projects .B projects
Lists all project names used, and the number of tasks for each. Lists all project names used, and the number of tasks for each.
@ -102,21 +102,9 @@ Shows a report of task history by month.
Shows a graphical report of task status by month. Shows a graphical report of task status by month.
.TP .TP
.B next .B calendar [ y | due [y] | month year [y] | year ]
Shows the most important pending tasks for each project.
.TP
.B calendar
Shows a monthly calendar with due tasks marked. Shows a monthly calendar with due tasks marked.
.TP
.B active
Shows all tasks that are started but not completed.
.TP
.B overdue
Shows all incomplete tasks that are beyond their due date.
.TP .TP
.B stats .B stats
Shows task database statistics. Shows task database statistics.
@ -145,8 +133,22 @@ Shows the long usage text.
.SH REPORT SUBCOMMANDS .SH REPORT SUBCOMMANDS
A report is a listing of information from the task database. There are several A report is a listing of information from the task database. There are several
built-in reports currently in task. The output and sort behaviour of these reports currently predefined in task. The output and sort behavior of these
subcommands can be configured in the configuration file. reports can be configured in the configuration file. See also the man page taskrc(5).
.TP
.B active [tags] [attrs] [description]
Shows all tasks matching the specified criteria
that are started but not completed.
.TP
.B all [tags] [attrs] [description]
Shows all tasks matching the specified criteria.
.TP
.B completed [tags] [attrs] [description]
Shows all tasks matching the specified criteria
that are completed.
.TP .TP
.B ls [tags] [attrs] [description] .B ls [tags] [attrs] [description]
@ -161,13 +163,30 @@ Provides a more detailed listing of tasks with specified criteria.
Provides the most detailed listing of tasks with specified criteria. Provides the most detailed listing of tasks with specified criteria.
.TP .TP
.B newest [tags] [attrs] [description] | newest [limit] .B newest [tags] [attrs] [description]
Shows the newest tasks with specified criteria. Shows the newest tasks with specified criteria.
.TP .TP
.B oldest [tags] [attrs] [description] | oldest [limit] .B oldest [tags] [attrs] [description]
Shows the oldest tasks with specified criteria Shows the oldest tasks with specified criteria
.TP
.B overdue [tags] [attrs] [description]
Shows all incomplete tasks matching the specified criteria
that are beyond their due date.
.TP
.B recurring [tags] [attrs] [description]
Shows all recurring tasks matching the specified criteria.
.TP
.B waiting [tags] [attrs] [description]
Shows all waiting tasks matching the specified criteria.
.TP
.B next [tags] [attrs] [description]
Shows all tasks with upcoming due dates matching the specified criteria.
.SH ATTRIBUTES AND METADATA .SH ATTRIBUTES AND METADATA
.TP .TP
@ -175,47 +194,82 @@ Shows the oldest tasks with specified criteria
Tasks can be specified uniquely by IDs, which are simply the index of the Tasks can be specified uniquely by IDs, which are simply the index of the
task in a report. Be careful, as the IDs of tasks may change after a task in a report. Be careful, as the IDs of tasks may change after a
modification to the database. Always run a report to check you have the right modification to the database. Always run a report to check you have the right
ID for a task. IDs can be given to task as a sequence, for example, ID for a task. IDs can be given to task as a sequences, for example,
.br .br
.B .B
task del 1 2 5-10,12 task del 1,4-10,19
.TP .TP
.B +tag|-tag .B +tag|-tag
Tags are arbitrary words associated with a task. Use + to add a tag and - to Tags are arbitrary words associated with a task. Use + to add a tag and - to
remove a tag from a task. remove a tag from a task. A task can have any quantity of tags
.TP .TP
.B project:<project-name> .B project:<project-name>
Specify the project to which a task is related to. Specifies the project to which a task is related to.
.TP .TP
.B priority:H|M|L|N .B priority:H|M|L|N
Specify High, Medium, Low and No priority for a task. Specifies High, Medium, Low and No priority for a task.
.TP .TP
.B due:<due-date> .B due:<due-date>
Specify the due-date of a task. Specifies the due-date of a task.
.TP
.B until:<end-date-of-recurrence>
Specify the Recurrence end-date of a task.
.TP .TP
.B recur:<frequency> .B recur:<frequency>
Specify the frequency of recurrence of a task. Specifies the frequency of a recurrence of a task.
.TP
.B until:<end-date-of-recurrence>
Specifies the Recurrence end-date of a task.
.TP .TP
.B fg:<color-spec> .B fg:<color-spec>
Specify foreground color. Specifies foreground color.
.TP .TP
.B bg:<color-spec> .B bg:<color-spec>
Specify background color. Specifies background color.
.TP .TP
.B rc:<path> .B limit:<number-of-rows>
Specify alternate configuration file. Specifies the desired number of rows a report should have.
.TP
.B wait:<wait-date>
Date until task becomes pending.
.SH ATTRIBUTE MODIFIERS
Attribute modifiers improve filters. Supported modifiers are:
.RS
.B before (synonyms under, below)
.br
.B after (synonyms over, above)
.br
.B none
.br
.B any
.br
.B is (synonym equals)
.br
.B isnt (synonym not)
.br
.B has (synonym contain)
.br
.B hasnt
.br
.B startswith (synonym left)
.br
.B endswith (synonym right)
.RE
For example:
.RS
task list due.before:eom priority.not:L
.RE
.SH SPECIFYING DATES AND FREQUENCIES .SH SPECIFYING DATES AND FREQUENCIES
@ -317,11 +371,50 @@ $ task l
could be list, ls or long. could be list, ls or long.
.SH SPECIFYING DESCRIPTIONS
Some task descriptions need to be escaped because of the shell
and the special meaning of some characters to the shell. This can be
done either by adding quotes to the description or escaping the special
character:
.RS
$ task add "quoted ' quote"
.br
$ task add escaped \\' quote
.RE
The argument \-\- (a double dash) tells task to treat all other args
as description:
.RS
$ task add -- project:Home needs scheduling
.RE
.SH CONFIGURATION FILE AND OVERRIDE OPTIONS
Task stores its configuration in a file in the user's home directory:
~/.taskrc . The default configuration file can be overridden with
.TP
.B task rc:<path-to-alternate-file>
Specifies an alternate configuration file.
.TP
.B task rc.<name>:<value> ...
Specifies individual configuration file overrides.
.SH EXAMPLES .SH EXAMPLES
For examples please see the online documentation at For examples please see the task tutorial man page at
.br
.RS
man task-tutorial
.RE
or the online documentation starting at
.RS
<http://taskwarrior.org/wiki/taskwarrior/Simple> <http://taskwarrior.org/wiki/taskwarrior/Simple>
.RE
.SH FILES .SH FILES
@ -338,19 +431,23 @@ can be configured in the configuration file.
.TP .TP
~/.task/completed.data The file that contains the completed "done" tasks. ~/.task/completed.data The file that contains the completed "done" tasks.
.TP
~/.task/undo.data The file that contains the information to the "undo" command.
.SH "CREDITS & COPYRIGHTS" .SH "CREDITS & COPYRIGHTS"
task was written by P. Beckingham <paul@beckingham.net>. task was written by P. Beckingham <paul@beckingham.net>.
.br .br
Copyright (C) 2006 \- 2009 P. Beckingham Copyright (C) 2006 \- 2009 P. Beckingham
This manpage was originally written by P.C. Shyamshankar, and has been modified This man page was originally written by P.C. Shyamshankar, and has been modified
and supplemented by Federico Hernandez. and supplemented by Federico Hernandez.
task is distributed under the GNU General Public License. See task is distributed under the GNU General Public License. See
http://www.gnu.org/licenses/gpl-2.0.txt for more information. http://www.gnu.org/licenses/gpl-2.0.txt for more information.
.SH SEE ALSO .SH SEE ALSO
.BR taskrc (5) .BR taskrc(5),
.BR task-tutorial(5)
For more information regarding task, the following may be referenced: For more information regarding task, the following may be referenced:

View file

@ -1,4 +1,4 @@
.TH taskrc 5 2009-05-14 "Task 1.7.1" "User Manuals" .TH taskrc 5 2009-07-14 "Task 1.8.0" "User Manuals"
.SH NAME .SH NAME
taskrc \- Configuration file for the task(1) command taskrc \- Configuration file for the task(1) command
@ -26,6 +26,14 @@ attribute when running task:
$ task rc:<directory-path>/.taskrc $ task rc:<directory-path>/.taskrc
.RE .RE
Individual option can be overridden by using the
.I rc.<name>:
attribute when running task:
.RS
$ task rc.<name>:<value> ...
.RE
If If
.B task .B task
is run without an existing configuration file it will ask if it should create a default, sample is run without an existing configuration file it will ask if it should create a default, sample
@ -53,24 +61,59 @@ and set a configuration variable to a certain value. The equal sign ("=") is use
name from the value to be set. name from the value to be set.
The hash mark, or pound sign ("#") is used as a "comment" character. It can be used to annotate the The hash mark, or pound sign ("#") is used as a "comment" character. It can be used to annotate the
configuration file. It is placed at the beginning of a line and all text after the character to the configuration file. All text after the character to the end of the line is ignored.
end of the line is ignored.
.SH CONFIGURATION VARIABLES .SH CONFIGURATION VARIABLES
Valid variable names and their default values are: Valid variable names and their default values are:
.SS FILES
.TP .TP
.B data.location=$HOME/.task .B data.location=$HOME/.task
This is a path to the directory containing all the task files. By default, it is set up to be ~/.task, This is a path to the directory containing all the task files. By default, it is set up to be ~/.task,
for example: /Users/paul/.task for example: /home/paul/.task
.TP
.B locking=on
Determines whether task uses file locking when accessing the pending.data and completed.data files.
Default to "on". Solaris users who store the task data files on an NFS mount may need to set locking
to "off". Note that setting this value to "off" is dangerous. It means that another program may write
to the task.pending file when task is attempting to do the same.
.SS TERMINAL
.TP
.B curses=on
Determines whether task uses ncurses to establish the size of the window you are
using, for text wrapping.
.TP
.B defaultwidth=80
The width of tables used when ncurses support is not available. Defaults to 80.
.TP
.B editor=vi
Specifies which text editor you wish to use for when the
.B task edit <ID>
command is used. Task will first look for this configuration variable. If found, it is used.
Otherwise task will look for the $VISUAL or $EDITOR environment variables, before it defaults
to using "vi".
.SS MISCELLANEOUS
.TP
.B locale=en-US
The locale is a combination of ISO 639-1 language code and ISO 3166 country
code. If not specified, task will assume en-US. If specified, task will locate
the correct file of localized strings and proceed. It is an error to specify a
locale for which there is no strings file.
.TP .TP
.B confirmation=yes .B confirmation=yes
May be "yes" or "no", and determines whether task will ask for confirmation before deleting a task. May be "yes" or "no", and determines whether task will ask for confirmation before deleting a task or doing bulk changes.
.TP .TP
.B echo.command=yes .B echo.command=yes
May be "yes" or "no", and causes task to display the ID and description of any task when you run the start, stop, do, undo, delete and undelete commands. The default value is "yes". May be "yes" or "no", and causes task to display the ID and description of any task when you run the start, stop, do, undo or delete commands. The default value is "yes".
.TP .TP
.B next=2 .B next=2
@ -78,6 +121,31 @@ Is a number, defaulting to 2, which is the number of tasks for each project that
.B task next .B task next
command. command.
.TP
.B bulk=2
Is a number, defaulting to 2. When more than this number of tasks are modified in a single command, confirmation will be required, unless the
.B confirmation
variable is "no".
.TP
.B nag=You have higher priority tasks.
This may be a string of text, or blank. It is used as a prompt when a task is completed
that is not considered high priority. The "task next" command lists important tasks, and
completing one of those does not generate this nagging. Default value is: You have higher
priority tasks.
.TP
.B complete.all.projects=yes
May be yes or no, and determines whether the tab completion scripts consider all the
project names you have used, or just the ones used in active tasks.
.TP
.B complete.all.tags=yes
May be yes or no, and determines whether the tab completion scripts consider all the
tag names you have used, or just the ones used in active tasks.
.SS DATES
.TP .TP
.B dateformat=m/d/Y .B dateformat=m/d/Y
This is a string of characters that define how task formats dates. The default value is: m/d/Y. This is a string of characters that define how task formats dates. The default value is: m/d/Y.
@ -110,19 +178,13 @@ m-d-y would output 07-24-09
.RE .RE
.TP .TP
.B monthsperline=99 .B weekstart=Sunday
Determines how many months the "task calendar" command renders across the screen. Determines the day a week starts. Valid values are Sunday or Monday only.
Defaults to however many will fit. If more months that will fit are specified,
task will only show as many that will fit.
.TP .TP
.B defaultwidth=80 .B displayweeknumber=yes
The width of tables used when ncurses support is not available. Defaults to 80. Determines if week numbers are displayed when using the "task calendar" command.
The week number is dependent on the day a week starts.
.TP
.B curses=on
Determines whether task uses ncurses to establish the size of the window you are
using, for text wrapping.
.TP .TP
.B due=7 .B due=7
@ -130,32 +192,23 @@ This is the number of days into the future that define when a task is considered
and is colored accordingly. Defaults to 7. and is colored accordingly. Defaults to 7.
.TP .TP
.B nag=You have higher priority tasks. .B monthsperline=2
This may be a string of text, or blank. It is used as a prompt when a task is completed Determines how many months the "task calendar" command renders across the screen.
that is not considered high priority. The "task next" command lists important tasks, and Defaults to however many will fit. If more months that will fit are specified,
completing one of those does not generate this nagging. Default value is: You have higher task will only show as many that will fit.
priority tasks.
.TP .SS COLOR CONTROLS
.B locking=on
Determines whether task uses file locking when accessing the pending.data and completed.data files.
Default to "on". Solaris users who store the task data files on an NFS mount may need to set locking
to "off". Note that setting this value to "off" is dangerous. It means that another program may write
to the task.pending file when task is attempting to do the same.
.TP
.B editor=vi
Specifies which text editor you wish to use for when the
.B task edit <ID>
command is used. Task will first look for this configuration variable. If found, it is used.
Otherwise task will look for the $VISUAL or $EDITOR environment variables, before it defaults
to using "vi".
.TP .TP
.B color=on .B color=on
May be "on" or "off". Determines whether task uses color. When "off", task will May be "on" or "off". Determines whether task uses color. When "off", task will
use dashes (-----) to underline column headings. use dashes (-----) to underline column headings.
.TP
.B fontunderline=on
Determines if font underlines or ASCII dashes should be used to underline
headers.
Task has a number of coloration rules. They correspond to a particular attribute Task has a number of coloration rules. They correspond to a particular attribute
of a task, such as it being due, or being active, and specifies the automatic of a task, such as it being due, or being active, and specifies the automatic
coloring of that task. A list of valid color, depending on your terminal, can be coloring of that task. A list of valid color, depending on your terminal, can be
@ -172,22 +225,31 @@ The coloration rules and their defaults are:
.RS .RS
.RS .RS
.B color.overdue=bold_red .B color.overdue=bold_red
The color for overdue tasks.
.br .br
.B color.due=bold_yellow .B color.due=bold_yellow
The color of due tasks.
.br .br
.B color.pri.H=bold .B color.pri.H=bold
The color of priority:H tasks.
.br .br
.B color.pri.M=on_yellow .B color.pri.M=on_yellow
The color of priority:M tasks.
.br .br
.B color.pri.L=on_green .B color.pri.L=on_green
The color of priority:L tasks.
.br .br
.B color.pri.none=white on_blue .B color.pri.none=white on_blue
The color of priority: tasks.
.br .br
.B color.active=bold_cyan .B color.active=bold_cyan
The color of active tasks.
.br .br
.B color.tagged=yellow .B color.tagged=yellow
The color of tagged tasks.
.br .br
.B color.recurring=on_red .B color.recurring=on_red
The color for recurring tasks.
.RE .RE
.RE .RE
@ -218,8 +280,22 @@ Colors any task assigned to project X.
.TP .TP
.B color.keyword.X=on_blue .B color.keyword.X=on_blue
Colors any task where the description contains X. Colors any task where the description contains X.
.TP
.B color.header=green
Colors any of the messages printed prior to the report output.
.TP
.B color.message=green
Colors any of the messages printed after the report output.
.TP
.B color.footnote=green
Colors any of the messages printed last.
.RE .RE
.SS SHADOW FILE
.TP .TP
.B .B
shadow.file=$HOME/.task/shadow.txt shadow.file=$HOME/.task/shadow.txt
@ -244,6 +320,8 @@ shadow.notify=on
When this value is set to "on", task will display a message whenever the shadow When this value is set to "on", task will display a message whenever the shadow
file is updated by some task command. file is updated by some task command.
.SS DEFAULTS
.TP .TP
.B .B
default.project=foo default.project=foo
@ -271,7 +349,7 @@ default.command=list project:foo
.RE .RE
.RS .RS
Then task will run the "list project:foo" command if no command is specified. This means that then task will run the "list project:foo" command if no command is specified. This means that
by merely typing by merely typing
.RE .RE
@ -289,111 +367,111 @@ ID Project Pri Description
.RE .RE
.RE .RE
The built in reports can be customized by using the following configuration variables. .SS REPORTS
The output columns, their labels and the sort order can be set using the corresponding
variables for each report. The reports can be customized by using the following configuration variables.
The output columns, their labels and the sort order can be set using the
corresponding variables for each report. Each report name is used as a
"command" name. For example
.TP .TP
.B .B task overdue
report.long.description
Lists all task, all data, matching the specified criteria
.TP .TP
.B .B report.X.description
report.long.labels=ID,Project,Pri,Added,Started,Due,Recur,Age,Tags,Description The description for report X when running the "task help" command.
.RE
.br
.B
report.long.columns=id,project,priority,entry,start,due,recur,age,tags,description
.br
.B
report.long.sort=due+,priority-,project+
.TP .TP
.B .B report.X.columns
report.list.description The columns that will be used when generating the report X. Valid columns are:
Lists all tasks matching the specified criteria id, uuid, project, priority, entry, start, due, recur, recur_ind, age, age_compact,
active, tags, description, description_only. The IDs are separated by commas.
.TP .TP
.B .B report.X.labels
report.list.labels=ID,Project,Pri,Due,Active,Age,Description The labels for each column that will be used when generating report X. The labels
.RE are a comma separated list.
.br
.B
report.list.columns=id,project,priority,due,active,age,description
.br
.B
report.list.sort=due+,priority-,project+
.TP .TP
.B .B report.X.sort
report.ls.description The sort order of the tasks in the generated report X. The sort order is specified
Minimal listing of all tasks matching the specified criteria by using the column ids post-fixed by a "+" for ascending sort order or a "-" for
descending sort order. The sort IDs are separated by commas
.TP .TP
.B .B report.X.filter
report.ls.labels=ID,Project,Pri,Description This adds a filter to the report X so that only tasks matching the filter criteria
.RE are displayed in the generated report.
.br
.B
report.ls.columns=id,project,priority,description
.br
.B
report.ls.sort=priority-,project+
.TP .TP
.B .B report.X.limit
report.newest.description An optional value to a report limiting the number of displayed tasks in the
Shows the newest tasks generated report.
.TP .TP
.B Task comes with a number of predefined reports in its default configuration file. These reports are:
report.newest.labels=ID,Project,Pri,Due,Active,Age,Description
.RE
.br
.B
report.newest.columns=id,project,priority,due,active,age,description
.br
.B
report.newest.sort=id-
.br
.B
report.newest.limit=10
.TP .TP
.B .B long
report.oldest.description Lists all task, all data, matching the specified criteria.
Shows the oldest tasks
.TP .TP
.B .B list
report.oldest.labels=ID,Project,Pri,Due,Active,Age,Description Lists all tasks matching the specified criteria.
.RE
.br .TP
.B .B ls
report.oldest.columns=id,project,priority,due,active,age,description Minimal listing of all tasks matching the specified criteria.
.br
.B .TP
report.oldest.sort=id+ .B newest
.br Shows the newest tasks.
.B
report.oldest.limit=10 .TP
.B oldest
Shows the oldest tasks.
.TP
.B overdue
Lists overdue tasks matching the specified criteria.
.TP
.B active
Lists active tasks matching the specified criteria.
.TP
.B completed
Lists completed tasks matching the specified criteria.
.TP
.B recurring
Lists recurring tasks matching the specified criteria.
.TP
.B waiting
Lists all waiting tasks matching the specified criteria.
.TP
.B all
Lists all tasks matching the specified criteria.
.TP
.B next
Lists all tasks with upcoming due dates matching the specified criteria.
.SH "CREDITS & COPYRIGHTS" .SH "CREDITS & COPYRIGHTS"
task was written by P. Beckingham <paul@beckingham.net>. task was written by P. Beckingham <paul@beckingham.net>.
.br .br
Copyright (C) 2006 \- 2009 P. Beckingham Copyright (C) 2006 \- 2009 P. Beckingham
This man page was originally written by Federico Hernandez. It is based on the task man page, which This man page was originally written by Federico Hernandez.
was originally written by P.C. Shyamshankar.
task is distributed under the GNU General Public License. See task is distributed under the GNU General Public License. See
http://www.gnu.org/licenses/gpl-2.0.txt for more information. http://www.gnu.org/licenses/gpl-2.0.txt for more information.
.SH SEE ALSO .SH SEE ALSO
.BR task(1) .BR task(1),
.BR task-tutorial(5)
For more information regarding task, the following may be referenced: For more information regarding task, the following may be referenced:

View file

@ -1,130 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>30-Second Tutorial</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="task.css" type="text/css" />
</head>
<body>
<div id="container">
<table>
<tr>
<td>
<div id="toolbar">
<a href="task.html">Home</a>
<a href="setup.html">Setup</a>
<a href="30second.html">30-second Tutorial</a>
<a href="simple.html">Simple</a>
<a href="advanced.html">Advanced</a>
<a href="shell.html">Shell</a>
<a href="config.html">Configuration</a>
<a href="color.html">Colors</a>
<a href="recur.html">Recurrence</a>
<a href="date.html">Date Handling</a>
<a href="faq.html">FAQ</a>
<a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div>
<div id="content">
<br />
<br />
<br />
<h2 class="title"><a name="simple">30-second Tutorial</a></h2>
<div class="content">
<p>
For the excessively lazy.
Add two tasks:
</p>
<pre><code>% task add Read task documents later
% task add priority:H Pay bills</code></pre>
<p>
Easy. See that second one has a High priority? Now let's look at those tasks:
</p>
<pre><code>% task ls
ID Project Pri Description
2 H Pay bills
1 Read task documents later</code></pre>
<p>
They are ordered by priority. Let's mark number 2 as done:
</p>
<pre><code>% task 2 done
% task ls
ID Project Pri Description
1 Read task documents later</code></pre>
<p>
Gone. Now let's delete that remaining task, because, well,
why bother now we are already using task:
</p>
<pre><code>% task delete 1
% task ls
No matches</code></pre>
<p>
Easy. But now consider checking out what task can really do...
</p>
</div>
<br />
<br />
<div class="content">
<p>
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>
</div>
</td>
<td align="right" valign="top" width="200px">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9709799404235424";
/* Task Main */
google_ad_slot = "8660617875";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-4737637-1");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>

View file

@ -1,541 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Advanced Usage</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="task.css" type="text/css" />
</head>
<body>
<div id="container">
<table>
<tr>
<td>
<div id="toolbar">
<a href="task.html">Home</a>
<a href="setup.html">Setup</a>
<a href="30second.html">30-second Tutorial</a>
<a href="simple.html">Simple</a>
<a href="advanced.html">Advanced</a>
<a href="shell.html">Shell</a>
<a href="config.html">Configuration</a>
<a href="color.html">Colors</a>
<a href="recur.html">Recurrence</a>
<a href="date.html">Date Handling</a>
<a href="faq.html">FAQ</a>
<a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div>
<div id="content">
<br />
<br />
<br />
<h2 class="title"><a name="advanced">Advanced Usage</a></h2>
<div class="content">
<p>
Here are the other commands, in some detail.
</p>
<strong>% task</strong>
<p>
With no arguments, this command will generate a help message that
lists all these commands.
</p>
<p>
However, if the following configuration variable is specified:
</p>
<pre><code>default.command=list pri:H</code></pre>
<p>
Then this command will be run whenever task is run without arguments.
This means that your most common task command can be run simply
with the command:
</p>
<pre><code>% task
[task list project:foo]
ID Project Pri Description
1 foo H Design the thing
2 foo Build the thing</code></pre>
<strong>% task projects</strong>
<p>
This report generates a list of all the different projects that you
are using along with a count of the pending tasks for each project.
For example:
</p>
<pre><code>% task projects
Project Tasks
Errands 1
Birthdays 3
Car 2</code></pre>
<strong>% task summary</strong>
<p>
This report lists all the projects and a summary of their task
status.
</p>
<pre><code>% task summary
Project Remaining Avg age Complete 0% 100%
Errands 1 3 days 50% XXXXXXXXXXXXXXXX
Birthdays 3 7 mths 0%
Car 2 2 wks 25% XXXXXXXXX</code></pre>
<p>
This shows the project, the remaining tasks, the average age of each
task, the percentage completed (remaining vs total) and a bar
indicating that percentage.
</p>
<strong>% task &lt;id&gt; append ...</strong>
<p>
Appends the additional description to an existing task.
</p>
<strong>% task annotate &lt;id&gt; additional note...</strong>
<p>
Allows an annotation to be attached to an existing task. Each
annotation has a time stamp, and when displayed, the annotations
are shown under the task description. For example:
</p>
<pre><code>% task add Go to the supermarket
% task annotate 1 need milk
% task ls
ID Project Pri Due Active Age Description
1 Go to the supermarket
3/23/2009 need milk</code></pre>
<p>
The date of the annotation uses the "dateformat" configuration
variable.
</p>
<strong>% task duplicate 1 /foo/bar/g +tag priority:H</strong>
<p>
This duplicates task 1, then applies the modifications specified,
which change all "foo" to "bar" in the description and annotations,
adds the tag "tag", and sets the priority to "H".
</p>
<strong>% task delete &lt;id&gt;</strong>
<p>
There are two ways of getting rid of tasks - mark them as done, or
delete them.
</p>
<strong>% task undelete &lt;id&gt;</strong>
<p>
If a task was inadvertently deleted, it may be undeleted, provided that no
reports have been run since the deletion. Ideally, the undelete command is
run immediately after the erroneous delete command.
</p>
<p>
If a report is run (such as "task list"), then task performs a garbage
collection that removes deleted tasks, and the task cannot be undeleted.
</p>
<strong>% task done &lt;id&gt;</strong>
<p>
This is how a task is marked as done.
</p>
<strong>% task undo &lt;id&gt;</strong>
<p>
If a task was recently marked as done, and no report has been run, it
may be possible to cancel the completed status of the task as though
"task done ..." was never run.
</p>
<strong>% task list ...</strong>
<p>
The list report will show the active status, and age of the task in
addition to the columns that "task ls" shows. It is just a more
detailed list.
</p>
<strong>% task long ...</strong>
<p>
The long report will show the entry date and start date of a task,
in addition to the columns that the "task list" shows.
</p>
<strong>% task start &lt;id&gt;</strong>
<p>
This marks a task as started (and therefore active), which is shown
in the "list" report:
</p>
<pre><code>% task list
ID Project Pri Due Active Age Description
12 Errand L Remember to deposit check
...
% task start 12
% task list
ID Project Pri Due Active Age Description
12 Errand L * 3 days Remember to deposit check
...</code></pre>
<strong>% task active</strong>
<p>
Shows all active tasks, that is, the tasks for which the
"task start ..." command was run, as shown above.
</p>
<strong>% task stop &lt;id&gt;</strong>
<p>
Marks a task as inactive, by removing the start time.
</p>
<strong>% task overdue</strong>
<p>
Simply lists all the task that have a due date that is past, in
"list" format.
</p>
<strong>% task history</strong>
<p>
This report shows you an overview of how many tasks were added,
completed and deleted, by month. It looks like this:
</p>
<pre><code>% task history
Year Month Added Completed Deleted Net
2008 March 21 16 0 5
April 13 11 1 1
May 8 14 3 -9</code></pre>
<p>
This shows that for the three months that task has been used, March
and April saw the total number of tasks increase, but in May the
number decreased as more task were completed than added.
</p>
<strong>% task ghistory</strong>
<p>
The ghistory report is a "graphical" version of the history
report. It shows a colored bar graph and legend.
</p>
<strong>% task timesheet 2</strong>
<p>
The timesheet report shows a list of tasks completed and started
during a one-week period. In the example above, 2 weeks of tasks
are shown.
</p>
<p>
By default, the report starts on a Monday. To override this
value, add an entry to your .taskrc file like this:
<pre><code>weekstart=Sunday</code></pre>
</p>
<strong>% task calendar</strong>
<p>
This report shows a calendar of the current month, with any task
due or overdue dates marked on it. Color is used to mark these
dates.
</p>
<pre><code>% task calendar
May 2008
Su Mo Tu We Th Fr Sa
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31</code></pre>
<strong>% task next</strong>
<p>
This report shows you the tasks you should probable work on next.
Task will scan all the tasks and will pick two task from each
project to report. Those two tasks will be chosen in order of
overdue, due soon, High, Medium or Low priority. Essentially task
chooses the two most important task for each project and displays
them ordered in the usual way.
</p>
<p>
If you wish to show a different number of tasks per project, modify
the entry in .taskrc:
</p>
<pre><code>next=2</code></pre>
<p>
To be your preferred number.
</p>
<strong>% task &lt;id&gt; ...</strong>
<p>
When a task id is specified, everything applies to just that task.
Suppose we needed to correct a task:
</p>
<pre><code>% task ls
ID Project Pri Description
12 Errand L Remember to deposit chekc
...
% task 12 Remember to deposit bonus check
% task ls
ID Project Pri Description
12 Errand L Remember to deposit bonus check
...</code></pre>
<strong>% task oldest [limit]</strong>
<p>
Lists the oldest tasks. The number of tasks shown is set by
the configuration variable:
<pre><code>report.oldest.limit=10</code></pre>
This value can be overridden at run time by specifying the
number of tasks on the command line:
<pre><code>task oldest 5</code></pre>
</p>
<strong>% task newest [limit]</strong>
<p>
Lists the newest tasks. The number of tasks shown is set by
the configuration variable:
<pre><code>report.newest.limit=10</code></pre>
This value can be overridden at run time by specifying the
number of tasks on the command line:
<pre><code>task newest 5</code></pre>
</p>
<strong>% task &lt;id&gt; /from/to/</strong>
<p>
If a task has been entered with a typo, it can be easily corrected
by this command. For example:
</p>
<pre><code>% task ls
ID Project Pri Description
12 Errand L Remember to deposit chekc
...
% task 12 /chekc/check/
% task ls
ID Project Pri Description
12 Errand L Remember to deposit check
...</code></pre>
<p>
This command makes a single correction to the first occurrence of
"from" in a task description.
</p>
<p>
If a task is annotated, the annotation can also be modified using
this command.
</p>
<strong>% task &lt;id&gt; /from/to/g</strong>
<p>
The "g" modifier to the substitution command causes every occurrence
of "from" to be replaced with "to", in both the description and any
annotations.
</p>
<strong>% task tags</strong>
<p>
This command will generate a list of all the tags that are currently
in use by task.
</p>
<strong>% task info &lt;id&gt;</strong>
<p>
This command gives detailed information about a single task. It
will tell you when the task was entered, when started, its status,
tags, and more.
</p>
<strong>% task stats</strong>
<p>
This command generates a list of statistics about your task usage,
such as the average time it takes to complete a task, how often new
tasks are added, and more.
</p>
<strong>% task completed</strong>
<p>
This generates a list of all tasks that have been completed, sorted
by their completion date.
</p>
<strong>% task export &lt;file name&gt;</strong>
<p>
This instructs task to write out a CSV format dump of all tasks,
both pending and completed, to the file specified. This is how you
might view tasks in a spreadsheet.
</p>
<strong>% task colors</strong>
<p>
This command displays all the colors that task supports.
</p>
<strong>% task version</strong>
<p>
This can be used to show the version number of task, and to display
all the current configuration settings, as read from the .taskrc
file.
</p>
<strong>% task rc:&lt;file&gt; ...</strong>
<p>
By specifying rc:<file>, it is possible to force task to use an alternate
.taskrc file. By default, task looks in your home directory, so these two
commands are essentially identical:
</p>
<pre><code>% task list
% task rc:~/.taskrc list</code></pre>
<p>
What this override allows, is the possibility of keeping your task lists
completely separate, say for work and home. This can be accomplished with
the following commands (valid for bash):
</p>
<pre><code>% alias htask="task rc:/home/me/.taskrc_home"
% alias wtask="task rc:/home/me/.taskrc_work"
% htask list
...
% wtask list
...</code></pre>
<strong>% task &lt;id&gt; "new description"</strong>
<p>
Not strictly a command, the replacement of the description can
be achieved by quoting the entire description. The quotes are
necessary in case one of the description words looks like a task
command.
</p>
<strong>% task &lt;id&gt; edit</strong>
<p>
This command allows you to use your text editor to edit all aspects
of a task. The specified task will be written to a file, and your
text editor will be invoked. If you modify the task in the text
editor, task will update accordingly.
</p>
<p>
Task will first check to see if you have defined a text editor
in the 'editor' configuration variable. If not, task will
check to see if you defined a text editor in the VISUAL
environment variable. If not task will check to see if you
defined a text editor in the EDITOR environment variable.
If all those fail, task launches vi.
</p>
<strong>% task &lt;id&gt; fg:... bg:...</strong>
<p>
Not strictly a command, the setting of the fg and bg (foreground
and background) attributes determines the colors used to represent
the task. Valid foreground colors are:
</p>
<pre><code> bold underline bold_underline
black bold_black underline_black bold_underline_black
red bold_red underline_red bold_underline_red
green bold_green underline_green bold_underline_green
yellow bold_yellow underline_yellow bold_underline_yellow
blue bold_blue underline_blue bold_underline_blue
magenta bold_magenta underline_magenta bold_underline_magenta
cyan bold_cyan underline_cyan bold_underline_cyan
white bold_white underline_white bold_underline_white</code></pre>
<p>
Note that these are not just colors, but combinations of colors and
attributes. Valid background colors are:
</p>
<pre><code>on_black on_bright_black
on_red on_bright_red
on_green on_bright_green
on_yellow on_bright_yellow
on_blue on_bright_blue
on_magenta on_bright_magenta
on_cyan on_bright_cyan
on_white on_bright_white</code></pre>
<p>
Note also that this capability does depend on whether your terminal
program can display these colors.
</p>
</div>
<br />
<br />
<div class="content">
<p>
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>
</div>
</td>
<td align="right" valign="top" width="200px">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9709799404235424";
/* Task Main */
google_ad_slot = "8660617875";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-4737637-1");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>

View file

@ -1,127 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Color Usage</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="task.css" type="text/css" />
</head>
<body>
<div id="container">
<table>
<tr>
<td>
<div id="toolbar">
<a href="task.html">Home</a>
<a href="setup.html">Setup</a>
<a href="30second.html">30-second Tutorial</a>
<a href="simple.html">Simple</a>
<a href="advanced.html">Advanced</a>
<a href="shell.html">Shell</a>
<a href="config.html">Configuration</a>
<a href="color.html">Colors</a>
<a href="recur.html">Recurrence</a>
<a href="date.html">Date Handling</a>
<a href="faq.html">FAQ</a>
<a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div>
<div id="content">
<br />
<br />
<br />
<h2 class="title"><a name="color">Colors</a></h2>
<div class="content">
<p>
Task supports color in several places. In cases where you may
specify a color, a foreground, a background, or a combination
foreground and background color may be used. The following are
valid foreground colors:
</p>
<pre><code> bold underline bold_underline
black bold_black underline_black bold_underline_black
red bold_red underline_red bold_underline_red
green bold_green underline_green bold_underline_green
yellow bold_yellow underline_yellow bold_underline_yellow
blue bold_blue underline_blue bold_underline_blue
magenta bold_magenta underline_magenta bold_underline_magenta
cyan bold_cyan underline_cyan bold_underline_cyan
white bold_white underline_white bold_underline_white</code></pre>
<p>
and the following are valid background colors:
</p>
<pre><code>on_black on_bright_black
on_red on_bright_red
on_green on_bright_green
on_yellow on_bright_yellow
on_blue on_bright_blue
on_magenta on_bright_magenta
on_cyan on_bright_cyan
on_white on_bright_white</code></pre>
<p>
Depending on your terminal color choices, task can display all
the colors it supports with the command:
</p>
<img src="images/color.png" />
</div>
<br />
<br />
<div class="content">
<p>
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>
</div>
</td>
<td align="right" valign="top" width="200px">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9709799404235424";
/* Task Main */
google_ad_slot = "8660617875";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-4737637-1");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>

View file

@ -1,445 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Task Configuration</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="task.css" type="text/css" />
</head>
<body>
<div id="container">
<table>
<tr>
<td>
<div id="toolbar">
<a href="task.html">Home</a>
<a href="setup.html">Setup</a>
<a href="30second.html">30-second Tutorial</a>
<a href="simple.html">Simple</a>
<a href="advanced.html">Advanced</a>
<a href="shell.html">Shell</a>
<a href="config.html">Configuration</a>
<a href="color.html">Colors</a>
<a href="recur.html">Recurrence</a>
<a href="date.html">Date Handling</a>
<a href="faq.html">FAQ</a>
<a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div>
<div id="content">
<br />
<br />
<br />
<h2 class="title"><a name="config">Configuring Task</a></h2>
<div class="content">
<p>
Task recognizes several entries in the .taskrc file for
configuration purposes. Valid entries are of the form:
</p>
<pre><code>name=value</code></pre>
<p>
Valid examples are:
</p>
<dt>data.location</dt>
<dd>
This is a path to the directory containing all the task files.
By default, it is set up to be ~/.task, for example:
/Users/paul/.task
</dd>
<dt>confirmation</dt>
<dd>
May be "yes" or "no", and determines whether task will ask for
confirmation before deleting a task.
</dd>
<dt>echo.command</dt>
<dd>
May be "yes" or "no", and causes task to display the ID and
description of any task when you run the start, stop, do, undo,
delete and undelete commands. The default value is "yes".
</dd>
<dt>nag</dt>
<dd>
This may be a string of text, or blank. It is used as a prompt
when a task is completed that is not considered high priority.
The "task next" command lists important tasks, and completing
one of those does not generate this nagging. Default value is:
<strong>Note: try to stick to high priority tasks. See "task next".</strong>
</dd>
<dt>next</dt>
<dd>
Is a number, defaulting to 2, which is the number of tasks for
each project that are shown in the "task next" command.
</dd>
<dt>curses</dt>
<dd>
Determines whether task uses ncurses to establish the size of
the window you are using, for text wrapping.
</dd>
<dt>blanklines</dt>
<dd>
May be "on" or "off". Prevents the display of unnecessary blank
lines so that task makes better use screen real estate on small-
screened devices.
</dd>
<dt>dateformat</dt>
<dd>
<p>
This is a string of characters that define how task formats dates.
The default value is:
</p>
<pre><code>m/d/Y</code></pre>
<p>
which means dates look like:
</p>
<pre><code>6/7/2008</code></pre>
<p>
The string should contain the characters:
<table>
<tr>
<th class="table_h">Character</th>
<th class="table_h">Meaning</th>
<th class="table_h">Example</th>
</tr>
<tr>
<td class="table_d">m</td>
<td class="table_d">minimal-digit month</td>
<td class="table_d">1, 12</td>
</tr>
<tr>
<td class="table_d">d</td>
<td class="table_d">minimal-digit day</td>
<td class="table_d">1, 30</td>
</tr>
<tr>
<td class="table_d">y</td>
<td class="table_d">two-digit year</td>
<td class="table_d">08</td>
</tr>
<tr>
<td class="table_d">M</td>
<td class="table_d">two-digit month</td>
<td class="table_d">01, 12</td>
</tr>
<tr>
<td class="table_d">D</td>
<td class="table_d">two-digit day</td>
<td class="table_d">01, 30</td>
</tr>
<tr>
<td class="table_d">Y</td>
<td class="table_d">four-digit year</td>
<td class="table_d">2008</td>
</tr>
</table>
</p>
<p>
The string may also contain other characters to act as spacers,
or formatting. Other values could include (but are not limited to):
</p>
<p>
<table>
<tr>
<th class="table_h">dateformat</td>
<th class="table_h">How it looks</th>
</tr>
<tr>
<td class="table_d">d/m/Y</td>
<td class="table_d">7/6/2008</td>
</tr>
<tr>
<td class="table_d">YMD</td>
<td class="table_d">20080607</td>
</tr>
<tr>
<td class="table_d">m-d-y</td>
<td class="table_d">6-7-08</td>
</tr>
</table>
</p>
</dd>
<dt>monthsperline</dt>
<dd>
Determines how many months the "task calendar" command
renders across the screen. Defaults to however many will
fit. If more months that will fit are specified, task will
only show as many that will fit.
</dd>
<dt>weekstart</dt>
<dd>
The day of the week that represents the first day of the week.
Defaults to "Monday".
</dd>
<dt>editor</dt>
<dd>
Specifies which text editor you wish to use for when the
<pre><code>task edit &lt;ID&gt;</code></pre>
command is used. Task will first look for this configuration
variable. If found, it is used. Otherwise task will look
for the VISUAL or EDITOR environment variables, before it
defaults to using 'vi'.
</dd>
<dt>defaultwidth</dt>
<dd>
The width of tables used when ncurses support is not available.
Defaults to 80.
</dd>
<dt>due</dt>
<dd>
This is the number of days into the future that define when a
task is considered due, and is colored accordingly.
Defaults to 7.
</dd>
<dt>color</dt>
<dd>
May be "on" or "off". Determines whether task uses color.
When "off", task will use dashes (-----) to underline column
headings.
</dd>
<dt>
color.overdue<br />
color.due<br />
color.pri.H<br />
color.pri.M<br />
color.pri.L<br />
color.pri.none<br />
color.active<br />
color.tagged<br />
color.recurring
</dt>
<dd>
These are the coloration rules. They correspond to a particular
attribute of a task, such as it being due, or being active, and
specifies the automatic coloring of that task. The value may
be one optional foreground color (see below) and one optional
background color. For example, the value may be:
<br />
<strong>bold_red on_bright_yellow</strong>
</dd>
<dt>color.tag.X</dt>
<dd>
Colors any task that has the tag X.
</dd>
<dt>color.project.X</dt>
<dd>
Colors any task assigned to project X.
</dd>
<dt>color.keyword.X</dt>
<dd>
Colors any task where the description contains X.
</dd>
<dt>default.project</dt>
<dd>
Provides a default project name for the "task add ..." command.
</dd>
<dt>default.priority</dt>
<dd>
Provides a default priority for the "task add ..." command.
</dd>
<dt>default.command</dt>
<dd>
<p>
Provides a default command that is run every time task is
invoked with no arguments. For example, if set to:
</p>
<pre><code>default.command=list project:foo</code></pre>
<p>
Then task will run the "list project:foo" command if no
command is specified. This means that by merely typing:
</p>
<pre><code>% task
[task list project:foo]
ID Project Pri Description
1 foo H Design the thing
2 foo Build the thing</code></pre>
<p>
Note that the value of this variable is simply the command
line that you would ordinarily type, but without the
preceding "task" program name.
</p>
</dd>
<dt>shadow.file</dt>
<dd>
<p>
If specified, designates a file path that will be autoamtically
written to by task, whenever the task database changes. In other
words, it is automatically kept up to date.
</p>
<p>
The shadow.command configuration variable is used to determine
which report is written to the shadow file. There is no color
used in the shadow file.
</p>
<p>
This feature can be useful in maintaining a current file for
use by the "Samurize" program.
</p>
</dd>
<dt>shadow.command</dt>
<dd>
<p>
This is the command that is run to maintain the shadow file,
determined by the shadow.file configuration variable. The
format is identical to that of default.command - please see
the documentation for default.command.
</p>
<p>
If this command is not specified, task will use the default.command
value instead. If that is not specified, the command "list" is used.
</p>
</dd>
<dt>shadow.notify</dt>
<dd>
When this value is set to "on", task will display a message
whenever the shadow file is updated by some task command.
</dd>
<dt>locking</dt>
<dd>
<p>
Determines whether task uses file locking when accessing the pending.data
and completed.data files. Default to "on". Solaris users who store
the task data files on an NFS mount may need to set locking to "off".
</p>
<p>
Note that setting this value to "off" is dangerous. It means that
another program may write to the task.pending file when task is
attempting to do the same.
</p>
</dd>
<dt>import.synonym.id</dt>
<dt>import.synonym.uuid</dt>
<dt>import.synonym.status</dt>
<dt>import.synonym.tags</dt>
<dt>import.synonym.entry</dt>
<dt>import.synonym.start</dt>
<dt>import.synonym.due</dt>
<dt>import.synonym.recur</dt>
<dt>import.synonym.end</dt>
<dt>import.synonym.project</dt>
<dt>import.synonym.priority</dt>
<dt>import.synonym.fg</dt>
<dt>import.synonym.bg</dt>
<dt>import.synonym.description</dt>
<dd>
If any of these configuration variables are found, they influence
data import by specifying a single additional field name synonym.
If a data import is failing because certain column names are not
being recognized, then this is how the field mapping can be
controlled.
</dd>
<p>
Note that the command:
</p>
<pre><code>task version</code></pre>
<p>
will display the configuration variables found in the .taskrc file,
and will warn you of any variables that are not recognized.
</p>
</div>
<br />
<br />
<div class="content">
<p>
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>
</div>
</td>
<td align="right" valign="top" width="200px">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9709799404235424";
/* Task Main */
google_ad_slot = "8660617875";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-4737637-1");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>

View file

@ -1,178 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Custom Reports</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="task.css" type="text/css" />
</head>
<body>
<div id="container">
<table>
<tr>
<td>
<div id="toolbar">
<a href="task.html">Home</a>
<a href="setup.html">Setup</a>
<a href="30second.html">30-second Tutorial</a>
<a href="simple.html">Simple</a>
<a href="advanced.html">Advanced</a>
<a href="shell.html">Shell</a>
<a href="config.html">Configuration</a>
<a href="color.html">Colors</a>
<a href="recur.html">Recurrence</a>
<a href="date.html">Date Handling</a>
<a href="faq.html">FAQ</a>
<a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div>
<div id="content">
<br />
<br />
<br />
<h2 class="title">Custom Reports</h2>
<div class="content">
<p>
Task allows you to customize reports, to a limited degree.
The "list", "long", "ls", "oldest" and "newest" reports are
all now custom reports, whereas in previous releases of task
they were not mutable. This means they can be modified,
renamed, or deleted.
</p>
<p>
More importantly, you can define your own. Here are the
three necessary items in the .taskrc file that define a new
report:
</p>
<code><pre>report.mine.description=Just the essentials
report.mine.columns=id,project,priority,description
report.mine.sort=priority-,project+</pre></code>
<p>
This defines a report, called "mine", that has four columns:
id, project, priority and description. It will be sorted on
two columns: by descending priority then ascending project.
The description that shows up in the task command usage page
is "Just the essentials". Because this report is called
"mine", it can be run with the command:
</p>
<code><pre>% task mine</pre></code>
<p>
An optional filter can also be specified like this:
</p>
<code><pre>report.mine.filter=priority:H +bug</pre></code>
<p>
This adds a filter so that only tasks with priority "H" and
with the "bug" tag are included in the report. This filter
definition is optional.
</p>
<p>
An optional limit can also be specified, which limits the
number of tasks shown in the report. If a limit is not
specified, then the number of tasks is not limited.
</p>
<code><pre>report.mine.limit=10</pre></code>
<p>
Here is a list of all the possible columns that may be included
in a report:
</p>
<p>
It is also possible to override the default columns names, if
the following line is added to your .taskrc file:
</p>
<pre><code>report.mine.labels=ID,Project,Priority,Description of task</code></pre>
<p>
Note that there must be the same number of labels as there are
columns to label, and they must appear in the same sequence.
</p>
<ul>
<li>id
<li>uuid
<li>project
<li>priority
<li>entry
<li>start
<li>due
<li>age
<li>active
<li>tags
<li>recur
<li>description_only
<li>description
<li>tag_indicator
<li>recurrence_indicator
</ul>
<p>
Custom reports will show up in the task command line usage.
</p>
</div>
<br />
<br />
<div class="content">
<p>
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>
</div>
</td>
<td align="right" valign="top" width="200px">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9709799404235424";
/* Task Main */
google_ad_slot = "8660617875";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-4737637-1");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>

View file

@ -1,160 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Date Handling</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="task.css" type="text/css" />
</head>
<body>
<div id="container">
<table>
<tr>
<td>
<div id="toolbar">
<a href="task.html">Home</a>
<a href="setup.html">Setup</a>
<a href="30second.html">30-second Tutorial</a>
<a href="simple.html">Simple</a>
<a href="advanced.html">Advanced</a>
<a href="shell.html">Shell</a>
<a href="config.html">Configuration</a>
<a href="color.html">Colors</a>
<a href="recur.html">Recurrence</a>
<a href="date.html">Date Handling</a>
<a href="faq.html">FAQ</a>
<a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div>
<div id="content">
<br />
<br />
<br />
<h2 class="title">Date Handling</h2>
<div class="content">
<p>
Task reads dates from the command line, and displays dates in the reports.
</p>
<p>
In order to do this in a flexible way, task obeys a configuration variable that
determines the expected and desired date format. See the
<a href="config.html">Configuring Task</a> page for details.
</p>
<p>
In addition to exactly specifying the date, such as:
</p>
<pre><code>% task ... due:7/10/2008</code></pre>
<p>
task supports a flexible variety of alternatives. For example:
</p>
<pre><code>% task ... due:today</code></pre>
<p>
Similarly:
</p>
<pre><code>% task ... due:yesterday
% task ... due:tomorrow</code></pre>
<p>
Here are some other forms that are accepted. The day number, followed by an
ordinal:
</p>
<pre><code>% task ... due:23rd</code></pre>
<p>
End of month:
</p>
<pre><code>% task ... due:eom</code></pre>
<p>
End of year:
</p>
<pre><code>% task ... due:eoy</code></pre>
<p>
End of week (Friday):
</p>
<pre><code>% task ... due:eow</code></pre>
<p>
Next Friday:
</p>
<pre><code>% task ... due:Friday</code></pre>
<p>
Note that next Friday means seven days from now if today is Friday, otherwise
it means the next occurring Friday. Most of these forms may be specified using
abbreviations, provided they are unique. For example:
</p>
<pre><code>% task ... due:fri</code></pre>
</div>
<br />
<br />
<div class="content">
<p>
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>
</div>
</td>
<td align="right" valign="top" width="200px">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9709799404235424";
/* Task Main */
google_ad_slot = "8660617875";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-4737637-1");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>

View file

@ -1,239 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Frequently Asked Questions</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="task.css" type="text/css" />
</head>
<body>
<div id="container">
<table>
<tr>
<td>
<div id="toolbar">
<a href="task.html">Home</a>
<a href="setup.html">Setup</a>
<a href="30second.html">30-second Tutorial</a>
<a href="simple.html">Simple</a>
<a href="advanced.html">Advanced</a>
<a href="shell.html">Shell</a>
<a href="config.html">Configuration</a>
<a href="color.html">Colors</a>
<a href="recur.html">Recurrence</a>
<a href="date.html">Date Handling</a>
<a href="faq.html">FAQ</a>
<a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div>
<div id="content">
<br />
<br />
<br />
<h2 class="title">Frequently Asked Questions</h2>
<div class="content">
<p>
(Actually, that's a misnomer. These are really Repeatedly Asked
Questions.)
</p>
<p>
<b>
Q: When I redirect the output of task to a file, I lose all
the colors. How do I fix this?
</b>
<br />
A: Task knows (or thinks it knows) when the output is not going
directly to a terminal, and strips out all the color control
characters. Prevent this with the following entry in your
.taskrc file:
<pre><code>_forcecolor=on</code></pre>
</p>
<hr>
<p>
<b>
Q: How do I backup my task data files? Where are they?
</b>
<br />
A: Task writes all pending tasks to the file ~/.task/pending.data
and all completed and deleted tasks to ~/.task/completed.data.
They are text files, so they can just be copied to another
location for safekeeping. Don't forget there is also the
~/.taskrc file that contains your task configuration data.
To be sure, and to future-proof your backup, consider backing
up all the files in the ~/.task directory.
</p>
<hr>
<p>
<b>
Q: How can I separate my work tasks from my home tasks?
Specifically, can I keep them completely separate?
</b>
<br />
A: You can do this by creating an alternate .taskrc file,
then using shell aliases. Here is are example Bash
commands to achieve this:
<pre><code>% cp ~/.taskrc ~/.taskrc_home
% (now edit .taskrc_home to change the value of data.location)
% alias wtask="task"
% alias htask="task rc:~/.taskrc_home"</code></pre>
This gives you two commands, 'wtask' and 'htask' that
operate using two different sets of task data files.
</p>
<hr>
<p>
<b>
Q: Can I revert to a previous version of task? How?
</b>
<br />
A: Yes, you can revert to a previous version of task,
simply by downloading an
<a href="versions.html">older version</a> and
installing it. If you find a bug in task, then this
may be the only way to work around the bug, until a
new release is made.
</p>
<p>
Note that it is possible that the task file format will
change. For example, the format changed between versions
1.5.0 and 1.6.0. Task will automatically upgrade the file
but if you need to revert to a previous version of task,
there is the file format to consider. This is yet another
good reason to back up your task data files!
</p>
<hr>
<p>
<b>
Q: I'm using Ubuntu 9.04, and I want task to word-wrap
descriptions. How do I do this?
</b>
<br />
A: You need to install ncurses, by doing this:
<code><pre>% sudo apt-get install libncurses5-dev</pre></code>
Then you need to rebuild task from scratch, starting with
<code><pre>% cd task-X.X.X
% ./configure
...</pre></code>
The result should be a task program that knows the width
of the terminal window, and wraps accordingly.
</p>
<hr>
<p>
<b>
Q: How do I build task under Cygwin?
</b>
<br />
A: Task is built the same way everywhere. But under Cygwin, you'll
need to make sure you have the following packages available
first:
<ul>
<li>gcc
<li>make
<li>libncurses-devel
<li>libncurses8
</ul>
The gcc and make packages allow you to compile the code, and
are therefore required, but the ncurses packages are optional.
Ncurses will allow task to determine the width of the window, and
therefore use the whole width and wrap text accordingly, for a
more aesthetically pleasing display.
</p>
<hr>
<p>
<b>
Q: Do colors work under Cygwin?
</b>
<br />
A: They do, but only in a limited way. You can use regular
foreground colors (black, red, green ...) and you can
regular background colors (on_black, on_red, on_green ...),
but underline and bold are not supported.
<br />
<br />
If you run the command:
<code><pre>% task colors</pre></code>
Task will display all the colors it can use, and you will
see which ones you can use.
<br />
<br />
See the <a href="color.html">color</a> documentation for
more details on which colors can be used.
</p>
<hr>
<!--
<p>
<b>
Q:
</b>
<br />
A:
</p>
<hr>
-->
</div>
<br />
<br />
<div class="content">
<p>
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>
</div>
</td>
<td align="right" valign="top" width="200px">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9709799404235424";
/* Task Main */
google_ad_slot = "8660617875";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-4737637-1");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>

View file

@ -1,132 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Task Filters</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="task.css" type="text/css" />
</head>
<body>
<div id="container">
<table>
<tr>
<td>
<div id="toolbar">
<a href="task.html">Home</a>
<a href="setup.html">Setup</a>
<a href="30second.html">30-second Tutorial</a>
<a href="simple.html">Simple</a>
<a href="advanced.html">Advanced</a>
<a href="shell.html">Shell</a>
<a href="config.html">Configuration</a>
<a href="color.html">Colors</a>
<a href="recur.html">Recurrence</a>
<a href="date.html">Date Handling</a>
<a href="faq.html">FAQ</a>
<a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div>
<div id="content">
<br />
<br />
<br />
<h2 class="title">Task Filters</h2>
<div class="content">
<p>
A task filter is a means of reducing a task report to a
subset that may consist of all tasks that have a specific
project, priority, tag, or part of the description.
</p>
<p>
A task filter consists of additional command line options,
that are specified in the same way as when a task is added.
</p>
<p>
All task reports can make use of filters.
</p>
<p>
For example, the report:
</p>
<code><pre>% task list</pre></code>
<p>
Lists all tasks.
</p>
<code><pre>% task list the</pre></code>
<p>
Lists only tasks with "the" in the task description.
</p>
<code><pre>% task list project:Home priority:H</pre></code>
<p>
Lists only tasks with both the "Home" project and "H" priority.
</p>
<code><pre>% task list +shopping</pre></code>
<p>
Lists only tasks with the "shopping" tag.
</p>
</div>
<br />
<br />
<div class="content">
<p>
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>
</div>
</td>
<td align="right" valign="top" width="200px">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9709799404235424";
/* Task Main */
google_ad_slot = "8660617875";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-4737637-1");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>

View file

@ -1,409 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>git</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="task.css" type="text/css" />
</head>
<body>
<div id="container">
<table>
<tr>
<td>
<div id="toolbar">
<a href="task.html">Home</a>
<a href="setup.html">Setup</a>
<a href="30second.html">30-second Tutorial</a>
<a href="simple.html">Simple</a>
<a href="advanced.html">Advanced</a>
<a href="shell.html">Shell</a>
<a href="config.html">Configuration</a>
<a href="color.html">Colors</a>
<a href="recur.html">Recurrence</a>
<a href="date.html">Date Handling</a>
<a href="faq.html">FAQ</a>
<a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div>
<div id="content">
<br />
<br />
<br />
<h2 class="title"><a name="simple">Using git</a></h2>
<div class="content">
<p>
First you need to tell git who you are. These commands will
write to ~/.gitconfig, and will be used to identify you when
you commit changes. Plus, I like color.
</p>
<pre><code>% git config --global user.name "John Doe"
% git config --global user.email "john@doe.com"
% git config --global color.ui=always</code></pre>
<p>
Now we will clone the repository, which involves downloading
about 2MB of files. Git repositories are very compact. We
will clone the repository from github. This takes a minute or
so.
</p>
<pre><code>% cd
% git clone git://github.com/pbeckingham/task.git task.git
% cd task.git</code></pre>
<p>
You just pulled the entire history of task changes since it
was uploaded to github. That will be missing about a year and
a half of prior changes, which were in Subversion. Let's
build task:
</p>
<pre><code>% autoreconf
...
% ./configure --prefix=/usr/local
...
% make
...</code></pre>
<p>
The task binary will be in the src directory. If you run:
</p>
<pre><code>% sudo make install</code></pre>
<p>
Then task will be copied to /usr/local/bin, according the
--prefix argument used above. /usr/local is the default
prefix, so that argument wasn't necessary, but illustrates
it's use.
</p>
<p>
Meanwhile, you have just created a local copy of the
repository. You can do anything to this copy except push to
github. Only the repository owner can push to github, or
additional users identified by the owner (with additional
monthly github fee). In order to get your changes back to
github, they have to go through the owner, either in the form
of a patch via email, or by creating your own github account,
pushing to you own task repository clone (github calls it a
fork), then asking the owner to pull directly from your
repository.
</p>
<p>
You only need to clone once, unless you feel like starting
over, or creating additional clones. Ordinarily, you update
your local copy by pulling changes from github with:
</p>
<pre><code>% git pull</code></pre>
<p>
Right now, nothing new should be pulled, because you just
cloned. Sometimes you'll see changes that have either been
made by the owner, or merged in from others, by the owner.
Let's take a look at the commit history:
</p>
<pre><code>% git log</code></pre>
<p>
You see a whole series of commits. Each commit is a set of
file changes that were made somewhere. Let's look at branches.
Try this:
</p>
<pre><code>% git branch
* master</code></pre>
<p>
This is telling you that you have only one branch, called
master. The asterisk tells you that this is your current
branch, which is redundant because you only have one. But
there are other branches on github. See those with:
</p>
<pre><code>% git branch -a
* master
remotes/origin/1.6.1
remotes/origin/1.7.0
remotes/origin/HEAD -&gt; origin/master
remotes/origin/master</code></pre>
<p>
A remote is what git calls another repository. The origin
remote is the repository that this clone originated from.
This output tells you that there is a 1.6.1 branch on github,
a 1.7.0 branch on github, and a master branch on github. It's
not obvious, but your local master (the first one shown) is
tracking remotes/origin/master, which means changes on the
remote will get merged to the local tracking branch on pull.
</p>
<p>
The convention used by task is to create a new branch whenever
work begins on a new version. When that version is released,
the branch is merged to master, but retained. At time of
writing, 1.6.1 is the currently released version of task, and
so remotes/origin/1.6.1 and remotes/origin/master are
currently identical, with all new development happening on the
1.7.0 branch. When 1.7.0 is released, it will get merged to
master, and the 1.6.1 branch will be deleted. Nothing will be
lost, because 1.6.1 is already merged to master. Let's look
at tags:
</p>
<pre><code>% git tag</code></pre>
...
v1.4.3
v1.5.0
v1.6.0
v1.6.1
<p>
Those tags are just labels that represent the last commit for
that version. You may notice that a change in the tag naming
convention, that occurred when the owner realized that git
will not allow a tag and a branch of the same name at the same
time, so now there is a "v" in the tags.
</p>
<p>
Let's make a branch called 1.7.0 that tracks changes to
remotes/origin/1.7.0. That means you can pull 1.7.0 changes
from github into your local branch, to keep up to date.
</p>
<pre><code>% git checkout -b 1.7.0 origin/1.7.0
Branch 1.7.0 set up to track remote branch 1.7.0 from origin.
Switched to a new branch '1.7.0'
% git branch -a
* 1.7.0
master
remotes/origin/1.6.1
remotes/origin/1.7.0
remotes/origin/HEAD -&gt; origin/master
remotes/origin/master</code></pre>
<p>
Now you can see that 1.7.0 is your current branch (*). That
means you are looking at the 1.7.0 codebase. Let us now
assume you intend to make a change, and submit the patch. We
will add Solaris 8 as a supported OS. This will affect two
files. First check status:
</p>
<pre><code>% git status
# On branch 1.7.0
nothing to commit (working directory clean)</code></pre>
<p>
No changes. That's what we expect. Now make the changes (any
editor will suffice, but assume vi):
</p>
<pre><code>% vi NEWS
% vi html/task.html</code></pre>
<p>
Now we expect to see changes. Status says:
</p>
<pre><code>% git status
# On branch 1.7.0
# Changed but not updated:
# (use "git add &lt;file&gt;..." to update what will be committed)
# (use "git checkout -- &lt;file&gt;..." to discard changes in working directory)
#
# modified: NEWS
# modified: html/task.html
#
no changes added to commit (use "git add" and/or "git commit -a")</code></pre>
<p>
Git sees that those two files have changed, but as git states,
they are not added to the commit. Git allows you to stage
changes, then commit the staged changes - a two-step process
that gives you complete control. Git also allows you to
commit all changes and bypass the staging, but that's a
shortcut that is risky, because you can inadvertently commit
things you didn't want to. Let's see what git thinks changed:
</p>
<pre><code>% git diff
diff --git a/NEWS b/NEWS
index 74adecd..30d4f8f 100644
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,7 @@ Task has been built and tested on the following configurations:
- Ubuntu 8.10 Intrepid Ibex
- Ubuntu 9.04 Jaunty Jackalope
- Arch Linux
+ - Solaris 8
- Solaris 10
- Cygwin 1.5.25-14
diff --git a/html/task.html b/html/task.html
index 66ee777..a2254f6 100644
--- a/html/task.html
+++ b/html/task.html
@@ -193,6 +193,7 @@
&lt;li&gt;Ubuntu 8.10 Intrepid Ibex
&lt;li&gt;Ubuntu 9.04 Jaunty Jackalope
&lt;li&gt;Arch Linux
+ &lt;li&gt;Solaris 8
&lt;li&gt;Solaris 10
&lt;li&gt;Cygwin 1.5.25-14
&lt;/ul&gt;</code></pre>
<p>
Git has correctly spotted the changes. The "git diff" command
always tells you the difference between the last commit and
the current state. Now we will stage the two changes:
</p>
<pre><code>% git add NEWS html/task.html
% git diff</code></pre>
<p>
No changes are reported. That's because if files are staged,
then diff shows the difference between the staged files and
the current state. We staged all changes, hence no diff. If
we wanted to see the difference between the last commit and
the staged files, try this:
</p>
<pre><code>% git diff --cached
(same as unstaged diff)</code></pre>
<p>
Now the status shows that the files are staged:
</p>
<pre><code>% git status
# On branch 1.7.0
# Changes to be committed:
# (use "git reset HEAD &lt;file&gt;..." to unstage)
#
# modified: NEWS
# modified: html/task.html
#</code></pre>
<p>
Now a commit command will commit the staged files:
</p>
<pre><code>% git commit -m "Added Solaris 8 as a supported platform"
[1.7.0 03308eb] Added Solaris 8 as a suported platform
2 files changed, 2 insertions(+), 0 deletions(-)</code></pre>
<p>
Now make a patch:
</p>
<pre><code>% git format-patch HEAD^
0001-Added-Solaris-8-as-a-supported-platform.patch</code></pre>
<p>
HEAD is a label that means the current head of the branch, or
in other words, what was last committed. HEAD^ means the
commit before that. HEAD~2 is the one before that, HEAD~3
etc. When we say create a patch of HEAD^, it means the same
as:
</p>
<pre><code>% git diff HEAD^</code></pre>
<p>
Which means show the difference between the previous commit
and the current commit, but the patch has extra identifying
information in it. Take a look at that patch file. If you
ran:
</p>
<pre><code>% git format-patch HEAD~10</code></pre>
<p>
Git will create 10 patch files, one for each commit. To get
the patch applied to the repository, email it to the owner.
The owner will then apply the patch with:
</p>
<pre><code>owner&gt; git apply 0001-Added-Solaris-8-as-a-supported-platform.patch</code></pre>
<p>
Then push the changes with:
</p>
<pre><code>owner&gt; git push</code></pre>
<p>
And that makes them available on github, which means in turn
that the next time you run:
</p>
<pre><code>% git pull</code></pre>
<p>
Your changes will have come full circle.
</p>
</div>
<br />
<br />
<div class="content">
<p>
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>
</div>
</td>
<td align="right" valign="top" width="200px">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9709799404235424";
/* Task Main */
google_ad_slot = "8660617875";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-4737637-1");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

View file

@ -1,157 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Data Import</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="task.css" type="text/css" />
</head>
<body>
<div id="container">
<table>
<tr>
<td>
<div id="toolbar">
<a href="task.html">Home</a>
<a href="setup.html">Setup</a>
<a href="30second.html">30-second Tutorial</a>
<a href="simple.html">Simple</a>
<a href="advanced.html">Advanced</a>
<a href="shell.html">Shell</a>
<a href="config.html">Configuration</a>
<a href="color.html">Colors</a>
<a href="recur.html">Recurrence</a>
<a href="date.html">Date Handling</a>
<a href="faq.html">FAQ</a>
<a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div>
<div id="content">
<br />
<br />
<br />
<h2 class="title">Data Import</h2>
<div class="content">
<p>
Tasks can be imported from files with this command:
<pre><code>% task import file</code></pre>
A variety of different file types are recognized by task, namely:
<ul>
<li>Tasks exported from task prior to version 1.5.0.
<li>Tasks exported from task version 1.5.0 and later. The file
format changed with 1.5.0.
<li>todo.sh files.
<li>CSV files with a variety of recognized column names.
<li>Plain text files, with one task listed per line.
<li>Task command line format.
</ul>
</p>
<p>
Task makes a good effort to determine which of these formats a
file is. It does this by reading the file, and looking for
familiar patterns. For example, the easiest files to recognize
are those exported from task itself, because they all have a
header line that comes in only three variations. Other formats
are a little harder to identify, but they all have their own
identifying characteristics.
</p>
<p>
The most complex import is when a CSV file is recognized.
Task needs a field header line in order to map columns to task
data items. For example, the if the following file is
imported:
</p>
<pre><code>number,status,task
1,pending,task one
2,pending,task two</code></pre>
<p>
Task will map the "number" field to task's "id" field, etc,
based on name. Task has a list of synonyms that it uses to
map fields, but you can specify your own override with any of
the following configuration variables:
</p>
<ul>
<li>import.synonym.id
<li>import.synonym.uuid
<li>import.synonym.status
<li>import.synonym.tags
<li>import.synonym.entry
<li>import.synonym.start
<li>import.synonym.due
<li>import.synonym.recur
<li>import.synonym.end
<li>import.synonym.project
<li>import.synonym.priority
<li>import.synonym.fg
<li>import.synonym.bg
<li>import.synonym.description
</ul>
<p>
Please note that it is wise to backup your task data files
before an import.
</p>
</div>
<br />
<br />
<div class="content">
<p>
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>
</div>
</td>
<td align="right" valign="top" width="200px">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9709799404235424";
/* Task Main */
google_ad_slot = "8660617875";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-4737637-1");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>

View file

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

View file

@ -1,219 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Recurring Tasks</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="task.css" type="text/css" />
</head>
<body>
<div id="container">
<table>
<tr>
<td>
<div id="toolbar">
<a href="task.html">Home</a>
<a href="setup.html">Setup</a>
<a href="30second.html">30-second Tutorial</a>
<a href="simple.html">Simple</a>
<a href="advanced.html">Advanced</a>
<a href="shell.html">Shell</a>
<a href="config.html">Configuration</a>
<a href="color.html">Colors</a>
<a href="recur.html">Recurrence</a>
<a href="date.html">Date Handling</a>
<a href="faq.html">FAQ</a>
<a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div>
<div id="content">
<br />
<br />
<br />
<h2 class="title">Recurring Tasks</h2>
<div class="content">
<p>
Task supports recurring tasks, which is a task that keeps falling due, on a
regular schedule. An example of this may be "pay rent". Here is how
recurring tasks work in task:
</p>
<p>
Ordinarily, a task is a single item that is entered in the pending state, and
remains so until it is either completed or deleted. This is an example of a
single instance task.
</p>
<p>
A recurring task is different. When a recurring task is entered, it remains
hidden from view, but acts as a root task for a task instances that are
generated on a regular basis. Consider the example:
</p>
<pre><code>% task add Pay rent due:7/1/2008 recur:monthly</code></pre>
<p>
If today's date is 7/10, for example, then that due date is in the past, and
you might expect there to be an already overdue task for 7/1/2008, and another
due on 8/1/2008. This means that from that root, task has created two
instances with different due dates.
</p>
<pre><code>% task list
ID Project Pri Due Active Age Description
1 7/1/2008 1 min Pay rent
2 8/1/2008 1 min Pay rent
2 tasks</code></pre>
<p>
Task creates any overdue tasks, then creates one additional due task. These
new task instances are then completed or deleted as you normally would.
</p>
<p>
In the example above, a new task instance is created every month, and this will
repeat indefinitely. Task also supports an end date. Suppose you are taking
every Friday off work for the summer. You'll need to submit your TPS report on
Thursdays instead:
</p>
<pre><code>% task add TPS report due:thursday recur:weekly until:8/31/2008</code></pre>
<p>
This create a weekly recurring task that expires on 8/31/2008. What this means
is that after all those task instances have been created, then completed or
deleted, the root task will expire and disappear. Task will tell you what it
is doing when this happens.
</p>
<h4>Deletion</h4>
<p>
When a recurring task is deleted, you will be asked if you would also like to
delete all recurring task instances:
</p>
<pre><code>% task del 1
Permanently delete task? (y/n) y
This is a recurring task. Do you want to delete all pending
recurrences of this same task? (y/n) y</code></pre>
<h4>Modification</h4>
<p>
When a recurring task is modified, all the other recurring task instances will
be modified. For example, if you raise the priority of one of the recurring
task instances, all will be modified.
</p>
<h4>Recurrence Periods</h4>
<p>
In the above examples, the recurrence period was specified as "monthly" and
"weekly". Task supports several ways of specifying this:
</p>
<table>
<tr>
<th class="table_h">Period</th>
<th class="table_h">Meaning</th>
</tr>
<tr>
<td class="table_d">daily, day, 1d, 2d ...</td>
<td class="table_d">Every day, or a number of days</td>
</tr>
<tr>
<td class="table_d">weekdays</td>
<td class="table_d">
Monday, Tuesday, Wednesday, Thursday and Friday,
skipping weekend days
</td>
</tr>
<tr>
<td class="table_d">weekly, 1w, 2w ...</td>
<td class="table_d">Every week, or a number of weeks</td>
</tr>
<tr>
<td class="table_d">biweekly, fortnight</td>
<td class="table_d">Every two weeks</td>
</tr>
<tr>
<td class="table_d">monthly, 1m, 2m ...</td>
<td class="table_d">Every month, or a number of months</td>
</tr>
<tr>
<td class="table_d">bimonthly</td>
<td class="table_d">Every two months</td>
</tr>
<tr>
<td class="table_d">quarterly, 1q, 2q ...</td>
<td class="table_d">Every three months, a quarter, or a number of quarters</td>
</tr>
<tr>
<td class="table_d">semiannual</td>
<td class="table_d">Every six months</td>
</tr>
<tr>
<td class="table_d">annual, yearly, 1y, 2y ...</td>
<td class="table_d">Every year, or a number of years</td>
</tr>
<tr>
<td class="table_d">biannual, biyearly, 2y</td>
<td class="table_d">Every two-years</td>
</tr>
</table>
</div>
<br />
<br />
<div class="content">
<p>
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>
</div>
</td>
<td align="right" valign="top" width="200px">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9709799404235424";
/* Task Main */
google_ad_slot = "8660617875";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-4737637-1");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>

View file

@ -1,154 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Task Usage</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="task.css" type="text/css" />
</head>
<body>
<div id="container">
<table>
<tr>
<td>
<div id="toolbar">
<a href="task.html">Home</a>
<a href="setup.html">Setup</a>
<a href="30second.html">30-second Tutorial</a>
<a href="simple.html">Simple</a>
<a href="advanced.html">Advanced</a>
<a href="shell.html">Shell</a>
<a href="config.html">Configuration</a>
<a href="color.html">Colors</a>
<a href="recur.html">Recurrence</a>
<a href="date.html">Date Handling</a>
<a href="faq.html">FAQ</a>
<a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div>
<div id="content">
<br />
<br />
<br />
<h1 class="title">ID Sequences</h1>
<div class="content">
<p>
Some task commands require an ID to be specified. For example:
</p>
<pre><code>% task 3 done</code></pre>
<p>
This marks a single task as done. But if you wanted to mark
several tasks as done, you could use:
</p>
<pre><code>% task 3,4,5 done</code></pre>
<p>
Which would mark tasks 3, 4 and 5 as all done. In this example,
the three IDs are consecutive, which means you could also have
entered:
</p>
<pre><code>% task 3-5 done</code></pre>
<p>
Or in a more complex example:
</p>
<pre><code>% task 1,3-5,12 23-25 done</code></pre>
<p>
This would mark tasks 1, 3, 4, 5, 12, 23, 24 and 25 as done.
Note that this example uses two sequences, separated by a space.
</p>
<p>
You must be careful though. Task tries very carefully to do
the right thing when it interprets the command line, but must
still impose some rules so that it can unambiguously read the
command. If you use one or more sequences, then they must
appear on the command line adjacent to each other. If they
are separated by something else, then task assumes the second
and subsequent set is not a sequence. Here is an example
of this:
</p>
<pre><code>% task 3 Order part number 4-123</code></pre>
<p>
Clearly the 4-123 is a part number, and not a sequence.
Task is being asked to modify the description of task 3 to be
"Order part number 4-123". Note that the ID is separated
from the part number by something other than a sequence.
Here is a bad example that task will misinterpret:
</p>
<pre><code>% task 3 4-123 is back-ordered, try again next week</code></pre>
<p>
The intent here is that task 3 have its description modified to be
"4-123 is back-ordered, try again next week", but will be
misinterpreted as tasks 3, 4, 5, 6 ... 123 will all be modified
to have the description "is back-ordered, try again next week".
The solution is to quote the whole description:
</p>
<pre><code>% task 3 "4-123 is back-ordered, try again next week"</code></pre>
</div>
<br />
<br />
<div class="content">
<p>
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>
</div>
</td>
<td align="right" valign="top" width="200px">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9709799404235424";
/* Task Main */
google_ad_slot = "8660617875";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-4737637-1");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>

View file

@ -1,140 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Task Setup</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="task.css" type="text/css" />
</head>
<body>
<div id="container">
<table>
<tr>
<td>
<div id="toolbar">
<a href="task.html">Home</a>
<a href="setup.html">Setup</a>
<a href="30second.html">30-second Tutorial</a>
<a href="simple.html">Simple</a>
<a href="advanced.html">Advanced</a>
<a href="shell.html">Shell</a>
<a href="config.html">Configuration</a>
<a href="color.html">Colors</a>
<a href="recur.html">Recurrence</a>
<a href="date.html">Date Handling</a>
<a href="faq.html">FAQ</a>
<a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div>
<div id="content">
<br />
<br />
<br />
<h2 class="title"><a name="setup">Quick Setup</a></h2>
<div class="content">
<p>
Build the task program according to the directions in the INSTALL
file. This transcript illustrates a typical installation:
</p>
<pre><code>% ls
task-1.6.0.tar.gz
% gunzip task-1.6.0.tar.gz
% tar xf task-1.6.0.tar
% cd task-1.6.0
% ./configure
...
% make
...
% make install # (may require sudo, depending on --prefix)</code></pre>
<p>
(For those of you using <a href="http://www.cygwin.com">Cygwin</a>,
you need to make sure you have the "gcc" and "make" packages
available, which are found in the "devel" category. For more
task features, also make sure you have "libncurses-devel" and
"lincurse8".)
</p>
<p>
You need to make sure that the installed task program is in your
PATH environment variable.
</p>
<p>
Task reads a configuration file - called .taskrc in your home
directory - and stores pending and completed tasks in in a directory
specified in the configuration file.
</p>
<p>
The simplest way to get a configuration file and task directory is
to run task. On startup, task will check to see if it can find the
configuration file and task directory, and if not found, will ask
you whether it may create both.
</p>
<pre><code>% task version
A configuration file could not be found in /Users/paul/.taskrc
Would you like a sample .taskrc created, so task can proceed? (y/n) y
Done.
[then task will show version information]</code></pre>
</div>
<br />
<br />
<div class="content">
<p>
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>
</div>
</td>
<td align="right" valign="top" width="200px">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9709799404235424";
/* Task Main */
google_ad_slot = "8660617875";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-4737637-1");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>

View file

@ -1,128 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Task Shadow Files</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="task.css" type="text/css" />
</head>
<body>
<div id="container">
<table>
<tr>
<td>
<div id="toolbar">
<a href="task.html">Home</a>
<a href="setup.html">Setup</a>
<a href="30second.html">30-second Tutorial</a>
<a href="simple.html">Simple</a>
<a href="advanced.html">Advanced</a>
<a href="shell.html">Shell</a>
<a href="config.html">Configuration</a>
<a href="color.html">Colors</a>
<a href="recur.html">Recurrence</a>
<a href="date.html">Date Handling</a>
<a href="faq.html">FAQ</a>
<a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div>
<div id="content">
<br />
<br />
<br />
<h2 class="title">Task Shadow Files</h2>
<div class="content">
<p>
A shadow file is a text file containing a copy of a task
report. It is automatically maintained by task whenever
something changes in the task database.
</p>
<p>
This means there is always a current version of the task
report kept in a text file. Products such as
<a href="http://www.samurize.com">Samurize</a>,
<a href="http://www.mulle-kybernetik.com/software/MkConsole/">MkConsole</a>,
or
<a href="http://projects.tynsoe.org/en/geektool/">GeekTool</a>
can display this file on the computer desktop, so that it
is readily visible.
</p>
<p>
To use a shadow file, edit your .taskrc configuration file,
and add three entries as shown:
</p>
<pre><code>shadow.file=/path/to/file
shadow.command=list pri:H
shadow.notify=on</code></pre>
<p>
In this example the shadow file contains a report equivalent
to running "task list pri:H". Note that the third entry
causes a message to be displayed whenever task updates the
shadow file. It is optional.
</p>
<p>
You can use any task command that generates a report, and of
course, you can specify any file name, provided the directory
it resides in already exists.
</p>
</div>
<br />
<br />
<div class="content">
<p>
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>
</div>
</td>
<td align="right" valign="top" width="200px">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9709799404235424";
/* Task Main */
google_ad_slot = "8660617875";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-4737637-1");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>

View file

@ -1,130 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Interacting with the Shell</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="task.css" type="text/css" />
</head>
<body>
<div id="container">
<table>
<tr>
<td>
<div id="toolbar">
<a href="task.html">Home</a>
<a href="setup.html">Setup</a>
<a href="30second.html">30-second Tutorial</a>
<a href="simple.html">Simple</a>
<a href="advanced.html">Advanced</a>
<a href="shell.html">Shell</a>
<a href="config.html">Configuration</a>
<a href="color.html">Colors</a>
<a href="recur.html">Recurrence</a>
<a href="date.html">Date Handling</a>
<a href="faq.html">FAQ</a>
<a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div>
<div id="content">
<br />
<br />
<br />
<h2 class="title"><a name="shell">Interacting with the Shell</a></h2>
<div class="content">
<p>
Certain characters are interpreted by the shell. For example, the
"&amp;". If you wish to include the &amp; in a task description,
you need to escape it, so the shell doesn't interpret it. For
example:
</p>
<pre><code>% task add Buy bread &amp; milk</code></pre>
<p>
This command is an error because of the &amp;. The shell will
consider this to be two commands:
</p>
<pre><code>% task add Buy bread &amp;
% milk</code></pre>
<p>
The shell treats the &amp; character as an indicator that the
command is complete and should be run in the background. Then the
shell considers "milk" to be a command all by itself. Which it is
not. One way to get around this is to individually escape the &amp;
character:
</p>
<pre><code>% task add Buy bread \&amp; milk</code></pre>
<p>
Another is to quote the entire description, with either ' or "
characters:
</p>
<pre><code>% task add "Buy bread &amp; milk"</code></pre>
<p>
Task itself interprets the commands, and it too can make mistakes.
For example, any colon : character will be interpreted by task as a
delimiter between an attribute name and its value. Currently there
is no workaround for this.
</p>
</div>
<br />
<br />
<div class="content">
<p>
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>
</div>
</td>
<td align="right" valign="top" width="200px">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9709799404235424";
/* Task Main */
google_ad_slot = "8660617875";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-4737637-1");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>

View file

@ -1,355 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Simple Usage</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="task.css" type="text/css" />
</head>
<body>
<div id="container">
<table>
<tr>
<td>
<div id="toolbar">
<a href="task.html">Home</a>
<a href="setup.html">Setup</a>
<a href="30second.html">30-second Tutorial</a>
<a href="simple.html">Simple</a>
<a href="advanced.html">Advanced</a>
<a href="shell.html">Shell</a>
<a href="config.html">Configuration</a>
<a href="color.html">Colors</a>
<a href="recur.html">Recurrence</a>
<a href="date.html">Date Handling</a>
<a href="faq.html">FAQ</a>
<a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div>
<div id="content">
<br />
<br />
<br />
<h2 class="title"><a name="simple">Simple Usage</a></h2>
<div class="content">
<p>
Let us begin by adding some tasks:
</p>
<pre><code>% task add Book plane ticket
% task add Rent a tux
% task add Reserve a rental car
% task add Reserve a hotel room</code></pre>
<p>
That's it. You'll notice immediately that task has a very
minimalist interface. Let us take a look at those tasks:
</p>
<pre><code>% task ls
ID Project Pri Description
1 Book plane ticket
2 Rent a tux
3 Reserve a rental car
4 Send John a birthday card</code></pre>
<p>
The 'ls' command provides the most minimal list of tasks. Each
task has been given an id number, and you can see that there are no
projects or priorities assigned. Wait a minute - I own a tux, I
don't need to rent one. Let us delete task 2:
</p>
<pre><code>% task 2 delete
Permanently delete task? (y/n) y</code></pre>
<p>
Task wants you to confirm deletions. To remove the confirmation,
edit your .taskrc file and change the line:
</p>
<pre><code>confirmation=yes</code></pre>
<p>
to have a value of "no".
</p>
<p>
While the use of projects and priorities are not essential to
benefitting from task, they can be very useful when the list of
tasks grows large. Let's assign a project to these tasks:
</p>
<pre><code>% task 1 project:Wedding
% task 3 project:Wedding
% task 4 project:Family
% task ls
ID Project Pri Description
3 Family Send John a birthday card
2 Wedding Reserve a rental car
1 Wedding Book plane ticket</code></pre>
<p>
Notice that the id numbers have changed. When tasks get deleted,
or have their attributes changed (project, for example), the ids are
prone to change. But the id numbers will remain valid until the
next 'ls' command is run. You should only use the ids from the most
recent 'ls' command. The ids change, because task is always trying
to use small numbers so that it is easy for you to enter them
correctly. Now that projects are assigned, we can look at just the
Wedding project tasks:
</p>
<p>
Subprojects are supported. If you have a project "Wedding", you can
specify that a task is a subproject "Transport" of "Wedding" by
assigning the project "Wedding.Transport". Let's do this:
</p>
<pre><code>% task 2 project:Wedding.Transport
% task ls
ID Project Pri Description
3 Family Send John a birthday card
2 Wedding.Transport Reserve a rental car
1 Wedding Book plane ticket</code></pre>
<p>
Task matches the leftmost part of the project when searching, so
projects may be abbreviated:
</p>
<pre><code>% task ls project:Wedding.Tra
ID Project Pri Description
2 Wedding.Transport Reserve a rental car</code></pre>
<p>
This way of matching projects can be used to see all tasks under
the "Wedding" project and all subprojects:
</p>
<pre><code>% task ls project:Wedding
ID Project Pri Description
2 Wedding.Transport Reserve a rental car
1 Wedding Book plane ticket</code></pre>
<p>
Let's reassign 2 back to the "Wedding" project:
</p>
<pre><code>% task 2 project:Wedding</code></pre>
<p>
Now that projects are assigned, we can look at just the
Wedding project tasks:
</p>
<pre><code>% task ls project:Wedding
ID Project Pri Description
1 Wedding Book plane ticket
2 Wedding Reserve a rental car</code></pre>
<p>
Any command arguments after the 'ls' are used for filtering the
output. We could also have requested:
</p>
<pre><code>% task ls ticket plane
ID Project Pri Description
1 Wedding Book plane ticket</code></pre>
<p>
Now let's prioritize. Priorities can be H, M or L (High, Medium,
Low).
</p>
<pre><code>% task ls
ID Project Pri Description
3 Family Send John a birthday card
2 Wedding Reserve a rental car
1 Wedding Book plane ticket
% task 1 priority:H
% task 2 prior:M
% task 3 pr:H
Ambiguous attribute 'pr' - could be either of project, priority
% task 3 pri:H
% task ls
ID Project Pri Description
3 Family H Send John a birthday card
1 Wedding H Book plane ticket
2 Wedding M Reserve a rental car</code></pre>
<p>
Notice that task supports the abbreviation of words such as
priority, project. Priority can be abbreviated to pri, but not pr,
because it is ambiguous. Now that tasks have been prioritized, you
can see that the tasks are being sorted by priority, with the
highest priority tasks at the top.
</p>
<p>
These attributes can all be provided when the task is added, instead
of applying them afterwards, as shown. The following command shows
how to set all the attributes at once:
</p>
<pre><code>% task add project:Wedding priority:H Book plane ticket<code></pre>
<p>
The 'ls' command provides the least information for each task. The
'list' command provides more:
</p>
<pre><code>% task list
ID Project Pri Due Active Age Description
3 Family H 4 mins Send John a birthday card
1 Wedding H 5 mins Book plane ticket
2 Wedding M 5 mins Reserve a rental car</code></pre>
<p>
Notice that a task can have a due date, and can be active. The
task lists are sorted by due date, then priority. Let's add due
dates:
</p>
<pre><code>% task 3 due:6/25/2008
% task 1 due:7/31/2008
% task list
ID Project Pri Due Active Age Description
3 Family H 6/25/2008 6 mins Send John a birthday card
1 Wedding H 7/31/2008 7 mins Book plane ticket
2 Wedding M 7 mins Reserve a rental car</code></pre>
<p>
If today's date is 6/23/2008, then task 3 is due in 2 days. It will
be colored yellow if your terminal supports color. To change this
color, edit your .taskrc file, and change the line to one of these
alternatives:
</p>
<pre><code>color.due=red
color.due=on_blue
color.due=red on_blue
color.due=bold_red on_blue</code></pre>
<p>
Where color is one of the following:
</p>
<pre><code>black
blue
red
green
cyan
magenta
yellow
white</code></pre>
<p>
All colors are specified in this way. Take a look in .taskrc for
all the other color rules that you control.
</p>
<p>
Tagging tasks is a good way to group them, aside from specifying a
project. To add a tag to a task:
</p>
<pre><code>% task &lt;id&gt; +tag<code></pre>
<p>
The plus sign indicates that this is a tag. Any number of tags may
be applied to a task, and then used for searching. Tags are just
single words that are labels.
</p>
<pre><code>% task list
ID Project Pri Due Active Age Description
3 Family H 6/25/2008 8 mins Send John a birthday card
1 Wedding H 7/31/2008 9 mins Book plane ticket
2 Wedding M 9 mins Reserve a rental car
% task 1 +phone
% task 2 +phone
% task 3 +shopping
% task 3 +john
% task list +phone
ID Project Pri Due Active Age Description
1 Wedding H 7/31/2008 9 mins Book plane ticket
2 Wedding M 9 mins Reserve a rental car</code></pre>
<p>
To remove a tag from a task, use the minus sign:
</p>
<pre><code>% task 3 -john</code></pre>
</div>
<br />
<br />
<div class="content">
<p>
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>
</div>
</td>
<td align="right" valign="top" width="200px">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9709799404235424";
/* Task Main */
google_ad_slot = "8660617875";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-4737637-1");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>

View file

@ -1,107 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Tab Completion</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="task.css" type="text/css" />
</head>
<body>
<div id="container">
<table>
<tr>
<td>
<div id="toolbar">
<a href="task.html">Home</a>
<a href="setup.html">Setup</a>
<a href="30second.html">30-second Tutorial</a>
<a href="simple.html">Simple</a>
<a href="advanced.html">Advanced</a>
<a href="shell.html">Shell</a>
<a href="config.html">Configuration</a>
<a href="color.html">Colors</a>
<a href="recur.html">Recurrence</a>
<a href="date.html">Date Handling</a>
<a href="faq.html">FAQ</a>
<a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div>
<div id="content">
<br />
<br />
<br />
<h2 class="title"><a name="simple">Tab Completion</a></h2>
<div class="content">
<p>
There is a Bash tab completion script distributed with task,
called task_completion.sh.
</p>
<p>
To install it, copy it to your
<code>/etc/bash_completion.d</code>
directory (in case you want to have it available system-wide)
and then
<pre><code>source /etc/bash_completion</code></pre>
or source it from your home directory's bashrc files.
</p>
</div>
<br />
<br />
<div class="content">
<p>
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>
</div>
</td>
<td align="right" valign="top" width="200px">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9709799404235424";
/* Task Main */
google_ad_slot = "8660617875";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-4737637-1");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>

View file

@ -1,126 +0,0 @@
body {
text-align: center;
margin: 0; padding: 1em;
}
#container {
width: 740px;
text-align: left;
margin: 0 auto; padding: 0;
}
#header {
height: 60px;
margin: 0 0 15px; padding: 0;
}
#page {}
#content {
width: 500px;
}
#header a:link,
#header a:visited {
color:#000;
text-decoration: none;
}
#header h1 {
font: bold 400% georgia, serif;
letter-spacing: -1px;
margin: 0;
float: left;
}
#header h2 {
font: normal 12px verdana, arial, sans-serif;
margin: 2.5em 0 0 0.8em;
float: left;
}
#content {}
#content h1,
#content h2,
#content h3,
#content h4,
#content h5 {
font-family: "lucidamac bold", "lucida grande", arial, sans-serif;
letter-spacing: -1px;
}
#content h1 {
font-size: 24px;
}
#content h2 {
font-size: 22px;
border-bottom: 1px dotted #000;
}
#content h3 {
font-size: 20px;
border-bottom: 1px dotted #bbb;
}
#content h4 {
font-size: 18px;
border-bottom: 1px dotted #bbb;
}
#content h5 {
font-size: 18px;
background: #ffd;
border-bottom: 1px dotted #bbb;
}
#content p {
line-height: 15px;
}
#content ul,
#content ol {
}
#content code {
font: normal 12px "bitstream vera sans mono", monaco "lucida console", "courier new", courier, serif;
}
#content pre {
color: #63FF00;
background: #000;
overflow: auto;
font: normal 12px "bitstream vera sans mono", monaco "lucida console", "courier new", courier, serif;
margin: 0.9em 0; padding: 8px;
}
dt {
font: bold 14px "lucida grande", verdana, arial, helvetica, sans-serif;
}
dd {
}
body {
font: normal 12px "lucida grande", verdana, arial, helvetica, sans-serif;
}
.small {
font: normal 10px verdana, arial, sans-serif;
}
.table_h {
background-color: #e0e0e0;
}
.table_d {
background-color: #f7f7f7;
}
input,
textarea { font: normal 12px "bitstream vera sans", verdana, sans-serif; }
abbr { border: none; }
cite { font-style: normal; }
a img { border: none; padding: 0; margin: 0; }

View file

@ -1,277 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Latest Release</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="task.css" type="text/css" />
</head>
<body>
<div id="container">
<table>
<tr>
<td>
<div id="toolbar">
<a href="task.html">Home</a>
<a href="setup.html">Setup</a>
<a href="30second.html">30-second Tutorial</a>
<a href="simple.html">Simple</a>
<a href="advanced.html">Advanced</a>
<a href="shell.html">Shell</a>
<a href="config.html">Configuration</a>
<a href="color.html">Colors</a>
<a href="recur.html">Recurrence</a>
<a href="date.html">Date Handling</a>
<a href="faq.html">FAQ</a>
<a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div>
<div id="content">
<br />
<br />
<br />
<h1 class="title">Task</h1>
<p>
Task is an open source, command-line, TODO list manager.
</p>
<p>
Here you will find information on how to acquire, build, configure,
use and become proficient with the task program.
</p>
<ul>
<li><a href="setup.html">Quick Setup</a>
<li><a href="30second.html">30-second Tutorial</a>
<li><a href="simple.html">Simple Usage</a>
<li><a href="advanced.html">Advanced Usage</a>
<li><a href="shell.html">Interacting with the Shell</a>
<li><a href="config.html">Configuring Task</a>
<li><a href="color.html">Color</a>
<li><a href="recur.html">Recurring Tasks</a>
<li><a href="date.html">Date Handling</a>
<li><a href="versions.html">Old Versions</a>
<li><a href="filter.html">Filters</a>
<li><a href="shadow.html">Shadow Files</a>
<li><a href="custom.html">Custom Reports</a>
<li><a href="import.html">Data Import</a>
<li><a href="faq.html">Frequently Asked Questions</a>
<li><a href="sequence.html">ID Sequences</a>
<li><a href="tab_completion.html">Tab Completion</a>
<li><a href="git.html">How to use git and contribute to task</a>
</ul>
<p>
More documents are being written, and will be added here.
</p>
<p>
Alternatively, watch the
<a href="http://www.youtube.com/watch?v=D2Kn4DMOVSw">task movie</a>
which illustrates many of task's features.
</p>
<p>
For the latest news, discussion of proposed task features, and
somewhere to voice your opinions, join us at
<a href="http://groups.google.com/group/taskprogram">http://groups.google.com/group/taskprogram</a>.
<table border=0 style="background-color: #fff; padding: 5px;" cellspacing=0>
<tr>
<td>
<img src="http://groups.google.com/groups/img/3nb/groups_bar.gif"
height=26 width=132 alt="Google Groups">
</td>
</tr>
<tr>
<td style="padding-left: 5px">
<b>Subscribe to taskprogram</b>
</td>
</tr>
<form action="http://groups.google.com/group/taskprogram/boxsubscribe">
<tr>
<td style="padding-left: 5px;">
Email:
<input type=text name=email>
<input type=submit name="sub" value="Subscribe">
</td>
</tr>
</form>
<tr>
<td align=right>
<a href="http://groups.google.com/group/taskprogram">Visit this group</a>
</td>
</tr>
</table>
</p>
<br />
<h2 class="title">Get the Latest Stable Release</h2>
<div class="content">
<table>
<tr>
<td>Source:</td>
<td><a href="http://www.beckingham.net/task-1.7.0.tar.gz">task-1.7.0.tar.gz</a></td>
</tr>
<!--
<tr>
<td>Mac OS X 10.5 (Leopard) Intel-only:</td>
<td><a href="http://www.beckingham.net/task-1.7.0.pkg">task-1.7.0.pkg</a></td>
</tr>
-->
<tr>
<td>
Ubuntu 9.04:
(Thanks to <a href="http://www.ultrafredde.com">Federico&nbsp;Hernandez</a>):
</td>
<td><a href="http://www.beckingham.net/task_1.7.0-0ubuntu1_i386.deb">task_1.7.0-0ubuntu1_i386.deb</a></td>
</tr>
<tr>
<td>
Red Hat:
(Thanks to <a href="http://www.ultrafredde.com">Federico&nbsp;Hernandez</a>):
</td>
<td><a href="http://www.beckingham.net/task-1.7.0-2.fc10.i386.rpm">task-1.7.0-2.fc10.i386.rpm</a></td>
</tr>
<tr>
<td>Git - get the whole source and history:</td>
<td><a href="http://github.com/pbeckingham/task">http://github.com/pbeckingham/task</a></td>
</tr>
</table>
<h4>New in version 1.7.0 (5/14/2009)</h4>
<ul>
<li>Improved the errors when parsing a corrupt or unrecognized pending.data
or completed.data file (thanks to T. Charles Yun).
<li>Added details to the "info" report about recurring tasks (thanks to T.
Charles Yun).
<li>Now writes a sample "defaultwidth" configuration variable to the default
.taskrc file (thanks to T. Charles Yun).
<li>Task allows commands that require an ID to now be given a sequence, which
is a set of IDs. This allows commands like "task delete 1 2 5-10,12".
<li>Fixed bug in the ghistory report, which caused it to only show a new
month if a task was added during that month.
<li>New command "duplicate" which allows an existing task to be duplicated,
and also have modifications applied (thanks to David J Patrick).
<li>The "append", and "done" commands now allow modifications to be applied
to the task(s) (thanks to David J Patrick).
<li>Improved word wrapping in various output.
<li>Fixed bug that added an extra line between header and graph in the
ghistory report.
<li>Added simple 'taskprogram' mailing list subscribe form to the web site.
<li>For custom reports that define a "limit" to the number of rows of output
such as "oldest" and "newest", task allows an override value. For
example "task oldest 5" will display the 5 oldest tasks.
<li>Modified the "stats" report so that it has the same aesthetics as the
other reports.
<li>New "timesheet" command displays tasks completed and started, per week,
and can display multiple weeks.
<li>New tab completion script, task_completion.sh, for bash users, is installed
to /usr/local/share/task (thanks to Federico Hernandez).
<li>Applied patch to allow task to build on Arch Linux (thanks to Johan Friis).
<li>Applied patch to fix a UUID bug on Solaris 8 (thanks to Steven de Brouwer).
<li>The task man page is now installed. Try "man task" (thanks to Federico
Hernandez and P.C. Shyamshankar).
<li>Fixed bug that causes task to create a default .task directory, even if
data.location specified otherwise (thanks to Federico Hernandez).
<li>New "edit" command that fires up a text editor (uses 'editor' configuration
variable, $VISUAL or $EDITOR environment variable) and allows direct
editing of all editable task details.
</ul>
<p>
(Find out <a href="versions.html">what was new in prior versions</a>)
</p>
<h2>Troubleshooting</h2>
<p>
Task has been built from source and tested in the following environments:
</p>
<p>
<ul>
<li>OS X 10.4 Tiger
<li>OS X 10.5 Leopard
<li>Fedora Core 8
<li>Fedora Core 9
<li>Fedora Core 10
<li>Ubuntu 7 Feisty Fawn
<li>Ubuntu 8 Hardy Heron
<li>Ubuntu 8.10 Intrepid Ibex
<li>Ubuntu 9.04 Jaunty Jackalope
<li>Arch Linux
<li>Slackware 12-12.2
<li>Solaris 8
<li>Solaris 10
<li>Cygwin 1.5.25-14
</ul>
</p>
<p>
If you have difficulties building task, have found a bug, have a
suggestion for improvement, or a feature request, please send mail to
<a href="mailto:task@beckingham.net">task@beckingham.net</a>.
</p>
<p>
Take a look at the <a href="faq.html">FAQ</a>
for tips and workarounds to problems.
</p>
</div>
<br />
<br />
<div class="content">
<p>
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>
</div>
</td>
<td align="right" valign="top" width="200px">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9709799404235424";
/* Task Main */
google_ad_slot = "8660617875";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-4737637-1");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>

View file

@ -1,486 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Task Prior Versions</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="task.css" type="text/css" />
</head>
<body>
<div id="container">
<table>
<tr>
<td>
<div id="toolbar">
<a href="task.html">Home</a>
<a href="setup.html">Setup</a>
<a href="30second.html">30-second Tutorial</a>
<a href="simple.html">Simple</a>
<a href="advanced.html">Advanced</a>
<a href="shell.html">Shell</a>
<a href="config.html">Configuration</a>
<a href="color.html">Colors</a>
<a href="recur.html">Recurrence</a>
<a href="date.html">Date Handling</a>
<a href="faq.html">FAQ</a>
<a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div>
<div id="content">
<br />
<br />
<br />
<h1 class="title">Task Prior Versions</h1>
<br />
<div class="content">
<h4>New in version 1.6.1 (4/24/2009)</h4>
<p>
<table>
<tr>
<td>Source:</td>
<td><a href="http://www.beckingham.net/task-1.6.1.tar.gz">task-1.6.1.tar.gz</a></td>
</tr>
<!--
<tr>
<td>Mac OS X 10.5 (Leopard) Intel-only:</td>
<td><a href="http://www.beckingham.net/task-1.6.1.pkg">task-1.6.1.pkg</a></td>
</tr>
<tr>
<td>
Debian:
(Thanks to <a href="http://blog.rfquerin.org">Richard&nbsp;Querin</a>):
</td>
<td><a href="http://www.beckingham.net/task_1.6.1-1_i386.deb">task_1.6.1-1_i386.deb</a></td>
</tr>
<tr>
<td>
Red Hat:
(Thanks to <a href="http://www.ultrafredde.com">Federico&nbsp;Hernandez</a>):
</td>
<td><a href="http://www.beckingham.net/task-1.6.1-1.FC10.i386.rpm">task-1.6.1-1.FC10.i386.rpm</a></td>
</tr>
-->
<tr>
<td>Git - get the whole source and history:</td>
<td><a href="http://github.com/pbeckingham/task">http://github.com/pbeckingham/task</a></td>
</tr>
</table>
<ul>
<li>Fixed bug that caused new, first-time .taskrc files to be written without
including the custom report labels (thanks to P.C. Shyamshankar).
</ul>
</p>
<h4>New in version 1.6.0 (4/13/2009)</h4>
<p>
<table>
<tr>
<td>Source:</td>
<td><a href="http://www.beckingham.net/task-1.6.0.tar.gz">task-1.6.0.tar.gz</a></td>
</tr>
<!--
<tr>
<td>Mac OS X 10.5 (Leopard) Intel-only:</td>
<td><a href="http://www.beckingham.net/task-1.6.0.pkg">task-1.6.0.pkg</a></td>
</tr>
<tr>
<td>
Debian:
(Thanks to <a href="http://blog.rfquerin.org">Richard&nbsp;Querin</a>):
</td>
<td><a href="http://www.beckingham.net/task_1.6.0-1_i386.deb">task_1.6.0-1_i386.deb</a></td>
</tr>
-->
<tr>
<td>
Red Hat:
(Thanks to <a href="http://www.ultrafredde.com">Federico&nbsp;Hernandez</a>):
</td>
<td><a href="http://www.beckingham.net/task-1.6.0-1.FC10.i386.rpm">task-1.6.0-1.FC10.i386.rpm</a></td>
</tr>
<tr>
<td>Git - get the whole source and history:</td>
<td><a href="http://github.com/pbeckingham/task">http://github.com/pbeckingham/task</a></td>
</tr>
</table>
<ul>
<li>Added support for new "append" command that adds more description text to
an existing task.
<li>Added support for the "weekdays" recurrence, which means a task can recur
five times a week, and not on weekends (thanks to Chris Pride).
<li>UTF8 text is now supported in task project names, tags and descriptions.
<li>Fixed bug that caused the y/n confirmation on task deletion to ignore the
Enter key and fail to re-prompt (thanks to Bruce Dillahunty).
<li>When the "echo.command" configuration variable is set to "yes", it causes
commands that modify tasks to display which task was affected (thanks to
Bruce Dillahunty).
<li>A task can now be annotated with the command "task <id> annotate ...", and
a timestamped annotation will appear in reports.
<li>A 'description_only' column is now available for use in custom reports,
and it excludes annotations.
<li>A task can now be upgraded to a recurring task by adding a recurrence
frequency, a due date, and an optional until date.
<li>When a recurring task is modified, all other instances of the recurring
task are also modified.
<li>Custom reports now support user-specified column labels (thanks to T.
Charles Yun).
<li>Task can now import tasks from a variety of data formats, including task
export files from versions 1.4.3 and earlier, versions 1.5.0 and later,
todo.sh 2.x, CSV, plain text and task command line. See online docs for
full details.
<li>Export was including 'id' in the column header even though it was not
included in the data.
<li>The task file format has changed slightly. Please back up your task
data files before upgrading to 1.6.0.
<li>Added new column 'recurrence_indicator' that displays an 'R' if the task
is a recurring task. This column can be added to any custom report.
<li>Added new column 'tag_indicator' that displays a '+' if the task
has any tags. This column can be added to any custom report.
<li>Fixed bug where sometimes a task description was concatenated oddly if
there was a colon somewhere in the description.
<li>Fixed bug that caused recurring annual tasks to exhibit a creeping due
date, because of an assumption of 365 days per year, which failed to
consider leap years (thanks to T. Charles Yun).
<li>Annotations can now be modified with the substitution commands /from/to/.
<li>Substitutions can now be made global with /from/to/g and all occurrences
of "from" will be replaced with "to".
</ul>
</p>
<p>
<h4>New in version 1.5.0 (3/15/2009)</h4>
<table>
<tr>
<td>Source:</td>
<td><a href="http://www.beckingham.net/task-1.5.0.tar.gz">task-1.5.0.tar.gz</a></td>
</tr>
<tr>
<td>Mac OS X 10.5 (Leopard) Intel-only:</td>
<td><a href="http://www.beckingham.net/task-1.5.0.pkg">task-1.5.0.pkg</a></td>
</tr>
<tr>
<td>
Debian:
(Thanks to <a href="http://blog.rfquerin.org">Richard&nbsp;Querin</a>):
</td>
<td><a href="http://www.beckingham.net/task_1.5.0-1_i386.deb">task_1.5.0-1_i386.deb</a></td>
</tr>
<tr>
<td>
Red Hat:
(Thanks to <a href="http://www.ultrafredde.com">Federico&nbsp;Hernandez</a>):
</td>
<td><a href="http://www.beckingham.net/task-1.5.0-1.i386.rpm">task-1.5.0-1.i386.rpm</a></td>
</tr>
</table>
<ul>
<li>Removed deprecated TUTORIAL file.
<li>Removed support for the "showage" configuration variable.
<li>"task stop" can remove the start time from a started task.
<li>"task ghistory" now displays a differently aligned graph, allowing
easier comparison by month of tasks added versus completed and deleted.
<li>"task version" command now reports unrecognized configuration variables,
which may be spelling mistakes or deprecated variables.
<li>"configure --enable-debug" now supported to suppress compiler optimization
to allow debugging.
<li>Allow lower case priorities, and automatically upper case them.
<li>Added support for "due" configuration variable which defines the number
of days in the future when a task is considered due.
<li>Added support for custom reports, comprised of a set of column names and
sort order, with optional filtering in the configuration file. This
means user-defined reports can be written, and the reports currently
in the configuration file can be renamed. Several of task's built in
reports have been converted to user-defined reports.
<li>New online documentation for custom reports.
<li>New algorithm for determining when the "nag" message is displayed.
<li>Fixed bug where task hangs with a certain combination of recurring tasks
and shadow files.
<li>Fixed bug with the task sort algorithm, which led to an unstable sequence
when there were only a handful of tasks.
<li>Performance enhanced by eliminating unnecessary sorting.
<li>Task now has a large (and growing) test suite and bug regression tests
to help ensure higher quality releases.
<li>Fixed bug that caused large performance hit during table rendering.
<li>Fixed bug that concatenated a modified description without spaces.
<li>Added new column 'recur' that displays the recurrence period of any
recurring tasks. This column can be added to any custom report.
<li>Added support for "color.recurring" configuration variable which
specifies the color of recurring tasks.
<li>Added support for "locking" configuration variable that controls whether
file locking is used.
<li>Task export feature now includes recurrence information, removes nested
quotes, and limits output to pending tasks.
<li>Task no longer includes deleted tasks in the summary report (thanks to
Benjamin Tegarden).
<li>Fixed bug that prevented the summary report from properly reporting
recently completed tasks.
</ul>
</p>
<p>
<h4>New in version 1.4.3 (11/1/2008)</h4>
<a href="http://www.beckingham.net/task-1.4.3.tar.gz">task-1.4.3.tar.gz</a>
<br />
Mac OS X 10.5 (Leopard) Intel-only:
<a href="http://www.beckingham.net/task-1.4.3.pkg">task-1.4.3.pkg</a>
<br />
Debian package: <a href="http://www.beckingham.net/task_1.4.3-1_i386.deb">task_1.4.3-1_i386.deb</a>
(Thanks to <a href="http://blog.rfquerin.org">Richard Querin</a>)
</p>
<p>
<ul>
<li>Fixed misleading task count at bottom of "info" report.
<li>Added support for a shadow file that contains a plain text task report,
with the "shadow.file" and "shadow.command" configuration variables.
The shadow file is automatically updated whenever the task database
changes. Useful for integrating with "Samurize".
<li>Task now displays a message whenever a shadow file is updated, if the
"shadow.notify" configuration variable is set "on".
<li>Fixed bug whereby adding a task with a \n, \r or \f did not fail properly.
<li>Removed "task usage" command.
<li>Added documentation for Shadow files.
<li>Added documentation for task filters.
</ul>
</p>
<p>
<h4>New in version 1.4.2 (9/18/2008)</h4>
<a href="http://www.beckingham.net/task-1.4.2.tar.gz">task-1.4.2.tar.gz</a>
<br />
Mac OS X 10.5 (Leopard) Intel-only:
<a href="http://www.beckingham.net/task-1.4.2.pkg">task-1.4.2.pkg</a>
<br />
Debian package: <a href="http://www.beckingham.net/task_1.4.2-1_i386.deb">task_1.4.2-1_i386.deb</a>
(Thanks to <a href="http://blog.rfquerin.org">Richard Querin</a>)
</p>
<ul>
<li>"task undo" can now retract a "task done" command, provided no
reports have been run.
<li>Task now correctly sorts on entire strings, instead of just the
first character (thanks to Andy Lester).
<li>Task now uses dashes (-----) to underline column headings when
color is disabled (thanks to Vincent Fleuranceau).
<li>Task now allows mixed case attribute names (pri:, PRI:, Pri: ...)
and commands (add, ADD, Add ...) (thanks to Vincent Fleuranceau).
<li>Task now supports a default project and priority for new tasks, via
the new "default.project" and "default.priority" configuration variables
(thanks to Vincent Fleuranceau).
<li>Task supports improved word-wrapping to the terminal width.
<li>Task now supports "default.command" configuration variable (for example
it could contain "list due:tomorrow") which is the command that is run
whenever task is invoked with no arguments.
<li>Task supports modifying the existing description of a task, with the
following syntax: task &lt;id&gt; "new description ...".
<li>Fixed bug so that relative dates in filters (task list due:eom,
task list due:tomorrow, task list due:23rd ...) are now properly
supported.
<li>Fixed bug so that source now properly includes &lt;string.h&gt; in
order to build clean using gcc 4.3 (thanks to H. İbrahim Güngör)
</ul>
<p>
<h4>New in version 1.4.1 (7/18/2008)</h4>
<a href="http://www.beckingham.net/task-1.4.1.tar.gz">task-1.4.1.tar.gz</a>
<br />
Mac OS X 10.5 (Leopard) Intel-only:
<a href="http://www.beckingham.net/task-1.4.1.pkg">task-1.4.1.pkg</a>
<br />
Debian package: <a href="http://www.beckingham.net/task_1.4.1-1_i386.deb">task_1.4.1-1_i386.deb</a>
(Thanks to <a href="http://blog.rfquerin.org">Richard Querin</a>)
</p>
<ul>
<li>Fixed bug: Descriptions could not be altered with "task 123 New description"
<li>Tweak: For "task calendar" month names are now centered over the month
<li>Removed TUTORIAL file contents in favor of online version
<li>New Mac Intel-only Leopard (10.5) binary package
</ul>
<p>
<h4>New in version 1.4.0 (7/10/2008)</h4>
Source: <a href="http://www.beckingham.net/task-1.4.0.tar.gz">task-1.4.0.tar.gz</a>
<br />
Debian package: <a href="http://www.beckingham.net/task_1.4.0-1_i386.deb">task_1.4.0-1_i386.deb</a>
(Thanks to <a href="http://blog.rfquerin.org">Richard Querin</a>)
</p>
<ul>
<li>Added new <a href="recur.html">recurring tasks</a> feature
<li>Added "task undelete" feature to restore a (very) recently deleted
task
<li>Added averages to the "task history" report
<li>Added bar chart history report "task ghistory"
<li>Added support for rc:&lt;file&gt; to allow override of the default
~/.taskrc file
<li>Added support for relative due: dates, such as "tomorrow", "friday",
"23rd", "eom"
<li>Added support for task filtering on all reports
<li>Automatically shuts off color, ncurses when output is not to a tty
<li>Added support for the ~ character in .taskrc data.location, for flexibility
<li>Allows colons on the description, provided what is to the left of the colon
is not a standard attribute name
<li>Fixed bug where Esc[0m sequences were being emitted for no good reason
<li>Fixed bug where table headers are underlined when color is turned off
<li>Fixed bug where adding a blank priority resulted in an assigned garbage value
<li>Fixed bug parsing date "07/08/2008" when using dateformat "m/d/Y"
</ul>
<p>
<h4>New in version 1.3.1</h4>
Source: <a href="http://www.beckingham.net/task-1.3.1.tar.gz">task-1.3.1.tar.gz</a>
<br />
Debian package: <a href="http://www.beckingham.net/task_1.3.1-1_i386.deb">task_1.3.1-1_i386.deb</a>
(Thanks to <a href="http://blog.rfquerin.org">Richard Querin</a>)
</p>
<ul>
<li>New configuration variable "defaultwidth" determines the width
of windows in the absense of ncurses support
<li>Fixed bug where "showage" configuration variable was not being
oberved by the "task long" report
<li>Fixed bug causing segmentation faults (mostly for Ubuntu users)
when various commands are run
<li>Fixed bug so that task now will recreate a missing ~/.taskrc file,
OR a missing ~/.task directory
</ul>
<p>
<h4>New in version 1.3.0</h4>
Source: <a href="http://www.beckingham.net/task-1.3.0.tar.gz">task-1.3.0.tar.gz</a>
<br />
Debian package: <a href="http://www.beckingham.net/task_1.3.0-0_i386.deb">task_1.3.0-0_i386.deb</a>
(Thanks to <a href="http://blog.rfquerin.org">Richard Querin</a>)
</p>
<ul>
<li>"task calendar" now displays multiple months per line, adjustable
by the "monthsperline" configuration variable. Feature added by
Damian Glenny
<li>Displays shorter message when a command is entered incorrectly,
and the full usage for "task help"
<li>"task export" can now filter tasks like the reports
<li>"task oldest" shows the oldest tasks
<li>"task newest" shows the newest tasks
<li>Fixed bug where task generates a segmentation fault for several
commands, when no "dateformat" configuration variable was present
<li>Fixed bug whereby if you have more than one task with a due date,
7 days gets added to the entry date of task 2..n
<li>Fixed bug whereby "1 wks" was being improperly pluralized
</ul>
<p>
<h4>New in version 1.2.0</h4>
Source: <a href="http://www.beckingham.net/task-1.2.0.tar.gz">task-1.2.0.tar.gz</a>
<br />
Debian package: <a href="http://www.beckingham.net/task_1.2.0-1_i386.deb">task_1.2.0-1_i386.deb</a>
(Thanks to <a href="http://blog.rfquerin.org">Richard Querin</a>)
</p>
<ul>
<li>Subprojects supported - please see documentation below, or TUTORIAL
file
<li>"dateformat" configuration variable now properly used to parse as
well as render dates
<li>"task list x" now performs a caseless comparison between "x" and
the task description
<li>"showage" configuration variable determines whether the "Age" column
should appear on the "task list" and "task next" reports
<li>Improvements to the TUTORIAL file and this page
</ul>
<p>
<h4>New in version 1.1.0</h4>
Source: <a href="http://www.beckingham.net/task-1.1.0.tar.gz">task-1.1.0.tar.gz</a>
<br />
Debian package: <a href="http://www.beckingham.net/task_1.1.0-1_i386.deb">task_1.1.0-1_i386.deb</a>
(Thanks to <a href="http://blog.rfquerin.org">Richard Querin</a>)
</p>
<ul>
<li>"blanklines" configuration variable to stop displaying unnecessary
white space and thus work better on small-screen devices
<li>"dateformat" configuration now determines how dates are formatted
<li>Better formatting of "task tags" output
<li>This home page set up, with TUTORIAL
<li>Added tags to the "task long" report
</ul>
<p>
<h4>New in version 1.0.1</h4>
Source: <a href="http://www.beckingham.net/task-1.0.1.tar.gz">task-1.0.1.tar.gz</a>
</p>
<ul>
<li>Fixed bug where the UUID generator not properly terminating strings
<li>Fixed bug where srandom/srand not called prior to custom UUID generation
</ul>
<p>
<h4>Version 1.0.0</h4>
Source: <a href="http://www.beckingham.net/task-1.0.0.tar.gz">task-1.0.0.tar.gz</a>
</p>
<p>
Task 1.0.0 was the first publicly available version of task.
</p>
</div>
<br />
<br />
<div class="content">
<p>
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>
</div>
</td>
<td align="right" valign="top" width="200px">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9709799404235424";
/* Task Main */
google_ad_slot = "8660617875";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-4737637-1");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>

157
i18n/strings.de-DE Normal file
View file

@ -0,0 +1,157 @@
# This is an example strings.en-US file.
#
# The task program has a built-in set of default strings, which are UTF8 encoded
# for the en-US locale. A file such as this is used to override those defaults.
# This means that a strings file is merely a delta applied to the built-in
# strings, so an empty string file means you get en-US.
#
# To use another string file, add the following entry to your .taskrc file:
#
# locale=sv-SE # Swedish string set
# 1xx task shell
100 Unbekannter Fehler #Unknown Error.
101 Konnte nicht Datenverzeichnis HOME aus passwd Datei lesen #Could not read home directory from the passwd file.
102 (j/n) #(y/n)
103 Ungültige ID in Sequenz #Invalid ID in sequence
104 Ungültige ID in Bereich #Invalid ID in range
105 Invertierter Sequenzbereich hoch-niedrig #Inverted sequence range high-low
106 ID Bereich zu gross #ID Range too large
107 Keine Sequenz #Not a sequence.
108 Task interaktiv nur möglich mit vorhandenem ncurses #Interactive task is only available when built with ncurses support.
109 Leerer Eintrag in der Eingabe #Empty record in input
110 Unbekanntes Zeichen am Zeilenende #Unrecognized characters at end of line
111 Datensatz nicht als Format 4 erkannt #Record not recognized as format 4
112 Kann leere Zeichenkette nicht ersetzen #Cannot substitute an empty string
113 Nicht erkanntes Zeichen am Ende der Ersetzung #Unrecognized character(s) at end of substitution
114 Fehlformulierte Ersetzung #Malformed substitution
115 Etiketten dürfen keine Kommas enthalten #Tags are not permitted to contain commas
# 2xx Commands - must be sequential
200 aktiv #active
201 hinzufen #add
202 beizufügen #append
203 anmerkung #annotate
204 kalender #calendar
205 farben #colors
206 fertiggestellt #completed
207 löschen #delete
208 erledigt #done
209 duplizieren #duplicate
210 editieren #edit
211 export #export
212 hilfe #help
213 geschichte #history
214 ggeschichte #ghistory
215 import #import
216 info #info
218 überfällig #overdue
219 projekte #projects
220 start #start
221 statistik #stats
222 stop #stop
223 zusammenfassung #summary
224 etikett #tags
225 zeitdatenblatt#timesheet
227 rücksetzen #undo
228 version #version
# 3xx Attributes - must be sequential
300 projekt #project
301 priorität #priority
302 vordergrund #fg
303 hintergrund #bg
304 fällig #due
305 eintrag #entry
306 start #start
307 stop #end
308 wiederkehrend #recur
309 bis #until
310 mask #mask
311 imask #imask
# 35x Attribute modifiers - must be sequential
350 davor #before
351 danach #after
352 nict #not
353 kein #none
354 beliebig #any
355 synth #synth
356 unter #under
357 über #over
358 erstes #first
359 letztes #last
360 dieses #this
361 nächste #next
362 ist #is
363 istnicht #isnt
364 hat #has
365 hatnicht #hasnt
366 beginntmit #startswith
367 endetmit #endswith
# 4xx Columns
# 5xx Colors
500 fett #bold
501 unterstrichen #underline
502 fett_unterstrichen #bold_underline
503 schwarz #black
504 rot #red
505 grün #green
506 gelb #yellow
507 blau #blue
508 magenta #magenta
509 cyan #cyan
510 weiss #white
511 fett_schwarz #bold_black
512 fett_rot #bold_red
513 fett_grün #bold_green
514 fett_gelb #bold_yellow
515 fett_blau #bold_blue
516 fett_magenta #bold_magenta
517 fett_cyan #bold_cyan
518 fett_weiss #bold_white
519 unterstrichen_schwarz #underline_black
520 unterstrichen_rot #underline_red
521 unterstrichen_grün #underline_green
522 unterstrichen_gelb #underline_yellow
523 unterstrichen_blau #underline_blue
524 unterstrichen_magenta #underline_magenta
525 unterstrichen_cyan #underline_cyan
526 unterstrichen_weiss #underline_white
527 fett_unterstrichen_schwarz #bold_underline_black
528 fett_unterstrichen_rot #bold_underline_red
529 fett_unterstrichen_grün #bold_underline_green
530 fett_unterstrichen_gelb #bold_underline_yellow
531 fett_unterstrichen_blau #bold_underline_blue
532 fett_unterstrichen_magenta #bold_underline_magenta
533 fett_unterstrichen_cyan #bold_underline_cyan
534 fett_unterstrichen_weiss #bold_underline_white
535 auf_schwarz #on_black
536 auf_rot #on_red
537 auf_grün #on_green
538 auf_gelb #on_yellow
539 auf_blau #on_blue
540 auf_magenta #on_magenta
541 auf_cyan #on_cyan
542 auf_weiss #on_white
543 auf_signal_schwarz #on_bright_black
544 auf_signal_rot #on_bright_red
545 auf_signal_grün #on_bright_green
546 auf_signal_gelb #on_bright_yellow
547 auf_signal_blau #on_bright_blue
548 auf_signal_magenta #on_bright_magenta
549 auf_signal_cyan #on_bright_cyan
550 auf_signal_weiss #on_bright_white
551 aus #off
552 Unbekannte Farbe #Unknown color name
# 6xx Config
# 7xx TDB
# 8xx Reports

159
i18n/strings.en-US Normal file
View file

@ -0,0 +1,159 @@
# This is an example strings.en-US file.
#
# The task program has a built-in set of default strings, which are UTF8 encoded
# for the en-US locale. A file such as this is used to override those defaults.
# This means that a strings file is merely a delta applied to the built-in
# strings, so an empty string file means you get en-US.
#
# To use another string file, add the following entry to your .taskrc file:
#
# locale=sv-SE # Swedish string set
# 1xx task shell
100 Unknown Error.
101 Could not read home directory from the passwd file.
102 (y/n)
103 Invalid ID in sequence
104 Invalid ID in range
105 Inverted sequence range high-low
106 ID Range too large
107 Not a sequence.
108 Interactive task is only available when built with ncurses support.
109 Empty record in input
110 Unrecognized characters at end of line
111 Record not recognized as format 4
112 Cannot substitute an empty string
113 Unrecognized character(s) at end of substitution
114 Malformed substitution
115 Tags are not permitted to contain commas
116 You must specify a command, or a task ID to modify
# 2xx Commands - must be sequential
200 active
201 add
202 append
203 annotate
204 calendar
205 colors
206 completed
207 delete
208 done
209 duplicate
210 edit
211 export
212 help
213 history
214 ghistory
215 import
216 info
218 overdue
219 projects
220 start
221 stats
222 stop
223 summary
224 tags
225 timesheet
227 undo
228 version
229 shell
# 3xx Attributes - must be sequential
300 project
301 priority
302 fg
303 bg
304 due
305 entry
306 start
307 end
308 recur
309 until
310 mask
311 imask
# 35x Attribute modifiers - must be sequential
350 before
351 after
352 not
353 none
354 any
355 synth
356 under
357 over
358 first
359 last
360 this
361 next
362 is
363 isnt
364 has
365 hasnt
366 startswith
367 endswith
# 4xx Columns
# 5xx Colors
500 bold
501 underline
502 bold_underline
503 black
504 red
505 green
506 yellow
507 blue
508 magenta
509 cyan
510 white
511 bold_black
512 bold_red
513 bold_green
514 bold_yellow
515 bold_blue
516 bold_magenta
517 bold_cyan
518 bold_white
519 underline_black
520 underline_red
521 underline_green
522 underline_yellow
523 underline_blue
524 underline_magenta
525 underline_cyan
526 underline_white
527 bold_underline_black
528 bold_underline_red
529 bold_underline_green
530 bold_underline_yellow
531 bold_underline_blue
532 bold_underline_magenta
533 bold_underline_cyan
534 bold_underline_white
535 on_black
536 on_red
537 on_green
538 on_yellow
539 on_blue
540 on_magenta
541 on_cyan
542 on_white
543 on_bright_black
544 on_bright_red
545 on_bright_green
546 on_bright_yellow
547 on_bright_blue
548 on_bright_magenta
549 on_bright_cyan
550 on_bright_white
551 off
552 Unknown color name
# 6xx Config
# 7xx TDB
# 8xx Reports

11
i18n/strings.es-ES Normal file
View file

@ -0,0 +1,11 @@
# 1xx task shell
100 Error desconocido.
# 2xx Commands
# 3xx Attributes
# 4xx Columns
# 5xx Colors
# 6xx Config
# 7xx TDB
# 8xx Reports

11
i18n/strings.fr-FR Normal file
View file

@ -0,0 +1,11 @@
# 1xx task shell
100 Erreur inconnue.
# 2xx Commands
# 3xx Attributes
# 4xx Columns
# 5xx Colors
# 6xx Config
# 7xx TDB
# 8xx Reports

11
i18n/strings.nl-NL Normal file
View file

@ -0,0 +1,11 @@
# 1xx task shell
100 Onbekende fout.
# 2xx Commands
# 3xx Attributes
# 4xx Columns
# 5xx Colors
# 6xx Config
# 7xx TDB
# 8xx Reports

157
i18n/strings.sv-SE Normal file
View file

@ -0,0 +1,157 @@
# This is an example strings.en-US file.
#
# The task program has a built-in set of default strings, which are UTF8 encoded
# for the en-US locale. A file such as this is used to override those defaults.
# This means that a strings file is merely a delta applied to the built-in
# strings, so an empty string file means you get en-US.
#
# To use another string file, add the following entry to your .taskrc file:
#
# locale=sv-SE # Swedish string set
# 1xx task shell
100 Okänt fel. #Unknown Error.
101 Kunde inte läsa hemkatalogen från passwd filen. #Could not read home directory from the passwd file.
102 (j/n) #(y/n)
103 Ogiltig ID i sekvens #Invalid ID in sequence
104 Ogiltig ID i spännvidd #Invalid ID in range
105 Inverterad sekvens spännvidd hög-låg #Inverted sequence range high-low
106 ID spännvidd för stor #ID Range too large
107 Ingen sekvens. #Not a sequence.
108 Interaktiv task är bara tillgänglig när den kompilerades med support för ncurses. #Interactive task is only available when built with ncurses support.
109 Tom post i ingångsdata #Empty record in input
110 Okänt tecknen på slutet av raden. #Unrecognized characters at end of line
111 Post inte indentifierad som format 4 #Record not recognized as format 4
112 Substitution av tom teckensträng är inte möjligt #Cannot substitute an empty string
113 Pkänt tecken vid slutet av substitution #Unrecognized character(s) at end of substitution
114 Ogiltig substitution #Malformed substitution
115 Taggar får inte innehåller komman #Tags are not permitted to contain commas
# 2xx Commands - must be sequential
200 aktivt #active
201 tillägg #add
202 bifoga #append
203 kommentera #annotate
204 kalender #calendar
205 färger #colors
206 avslutad #completed
207 stryk #delete
208 färdig #done
209 kopiera #duplicate
210 redigera #edit
211 exportera #export
212 hjälp #help
213 historia #history
214 ghistoria #ghistory
215 importera #import
216 info #info
218 försenad #overdue
219 projekten #projects
220 start #start
221 statistik #stats
222 stop #stop
223 sammanfattning #summary
224 taggar #tags
225 tidsrapport #timesheet
227 ångra #undo
228 version #version
# 3xx Attributes - must be sequential
300 projekt #project
301 prioritet #priority
302 förgrund #fg
303 bakgrund #bg
304 väntad #due
305 post #entry
306 start #start
307 slut #end
308 periodirskt #recur
309 innan #until
310 mask #mask
311 imask #imask
# 35x Attribute modifiers - must be sequential
350 före #before
351 efter #after
352 inte #not
353 ingen #none
354 några #any
355 synth #synth
356 under #under
357 över #over
358 första #first
359 sista #last
360 detta #this
361 nästa #next
362 är #is
363 ärinte #isnt
364 har #has
365 harinte #hasnt
366 börjarmed #startswith
367 slutarmed #endswith
# 4xx Columns
# 5xx Colors
500 fet #bold
501 understrykt #underline
502 fet_understrykt #bold_underline
503 svart #black
504 röd #red
505 grön #green
506 gul #yellow
507 blå #blue
508 magenta #magenta
509 cyan #cyan
510 vit #white
511 fet_svart #bold_black
512 fet_röd #bold_red
513 fet_grön #bold_green
514 fet_gul #bold_yellow
515 fet_blå #bold_blue
516 fet_magenta #bold_magenta
517 fet_cyan #bold_cyan
518 fet_vit #bold_white
519 understrykt_svart #underline_black
520 understrykt_röd #underline_red
521 understrykt_grön #underline_green
522 understrykt_gul #underline_yellow
523 understrykt_blå #underline_blue
524 understrykt_magenta #underline_magenta
525 understrykt_cyan #underline_cyan
526 understrykt_vit #underline_white
527 fet_understrykt_svart #bold_underline_black
528 fet_understrykt_röd #bold_underline_red
529 fet_understrykt_grön #bold_underline_green
530 fet_understrykt_gul #bold_underline_yellow
531 fet_understrykt_blå #bold_underline_blue
532 fet_understrykt_magenta #bold_underline_magenta
533 fet_understrykt_cyan #bold_underline_cyan
534 fet_understrykt_vit #bold_underline_white
535 på_svart #on_black
536 på_röd #on_red
537 på_grön #on_green
538 på_gul #on_yellow
539 på_blå #on_blue
540 på_magenta #on_magenta
541 på_cyan #on_cyan
542 på_vit #on_white
543 på_ljust_svart #on_bright_black
544 på_ljust_röd #on_bright_red
545 på_ljust_grön #on_bright_green
546 på_ljust_gul #on_bright_yellow
547 på_ljust_blå #on_bright_blue
548 på_ljust_magenta #on_bright_magenta
549 på_ljust_cyan #on_bright_cyan
550 på_ljust_vit #on_bright_white
551 av #off
552 Okänt färg namn #Unknown color name
# 6xx Config
# 7xx TDB
# 8xx Reports

5
i18n/tips.de-DE Normal file
View file

@ -0,0 +1,5 @@
%
erster Tipp
%
zweiter Tipp
%

5
i18n/tips.en-US Normal file
View file

@ -0,0 +1,5 @@
%
first tip
%
second tip
%

5
i18n/tips.sv-SE Normal file
View file

@ -0,0 +1,5 @@
%
första tips
%
andra tips
%

32
package-config/README Normal file
View file

@ -0,0 +1,32 @@
The package-config directory contains the configuration files
for building release packages for the different operating
systems:
* osx: binary packages for Mac OSX
* fedora: rpm packages for Fedora (Linux)
* ubuntu: deb packages for Ubuntu and (Linux)
* cygwin_ bz2 packages for cygwin (windows)
Please visit the corresponding operating systems homepage
for instructions on how to build a binary package of task
out of the released source tarball with these configuration
files.
For Fedora rpm packages you find instructions at
http://fedoraproject.org/wiki/PackageMaintainers/CreatingPackageHowTo
For Ubuntu deb packages you find instructions at
https://wiki.ubuntu.com/PackagingGuide/Complete
For Cygwin bz2 packages you find instructions at
http://cygwin.com/setup.html
You might also ask in the forums on taskwarrior.org if you
have further questions.
This file and the corresponding package build configuration files
are released 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.
Please see the file COPYING in the main directory.

View file

@ -0,0 +1,10 @@
# setup.hint for task 1.7.1-1
category: Utils
requires: libncurses9 cygwin
sdesc: A command-line to do list manager
ldesc: "Task is a command-line to do list manager.
It has support for GTD functionality and includes
the following features: tags, colorful tabular output,
reports and graphs, lots of manipulation commands,
low-level API, abbreviations for all commands and
options, multiuser file locking, recurring tasks."

View file

@ -0,0 +1,45 @@
task 1.7.1-1
------------------------------------------
A command-line to do list manager that can be used
with the gtd system.
Runtime requirements:
cygwin-1.5.25 or newer
libncurses
Build requirements:
cygwin-1.5.25 or newer
gcc-3.4.4-1 or newer
libncurses-devel
Canonical homepage:
http://taskwarrior.org
Canonical download:
http://taskwarrior.org/download
License:
GPLv2+
Language:
C++
------------------------------------
Build instructions:
unpack task-1.7.1-1-src.tar.bz2
if you use setup to install this src package,
it will be unpacked under /usr/src automatically
cd /usr/src/task-1.7.1-1
./configure --prefix=/usr
make
make install
------------------------------------
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 ----

View file

@ -0,0 +1,63 @@
diff -Nrup task-1.7.1-1/CYGWIN-PATCHES/setup.hint task-1.7.1-1.cygwin/CYGWIN-PATCHES/setup.hint
--- task-1.7.1-1/CYGWIN-PATCHES/setup.hint 1970-01-01 01:00:00.000000000 +0100
+++ task-1.7.1-1.cygwin/CYGWIN-PATCHES/setup.hint 2009-06-17 15:47:56.304750000 +0200
@@ -0,0 +1,10 @@
+# setup.hint for task 1.7.1-1
+category: Utils
+requires: libncurses9 cygwin
+sdesc: A command-line to do list manager
+ldesc: "Task is a command-line to do list manager.
+It has support for GTD functionality and includes
+the following features: tags, colorful tabular output,
+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
@@ -0,0 +1,45 @@
+task 1.7.1-1
+------------------------------------------
+
+A command-line to do list manager that can be used
+with the gtd system.
+
+Runtime requirements:
+ cygwin-1.5.25 or newer
+ libncurses
+
+Build requirements:
+ cygwin-1.5.25 or newer
+ gcc-3.4.4-1 or newer
+ libncurses-devel
+
+Canonical homepage:
+ http://taskwarrior.org
+
+Canonical download:
+ http://taskwarrior.org/download
+
+License:
+ GPLv2+
+
+Language:
+ C++
+
+------------------------------------
+
+Build instructions:
+ unpack task-1.7.1-1-src.tar.bz2
+ if you use setup to install this src package,
+ it will be unpacked under /usr/src automatically
+ cd /usr/src/task-1.7.1-1
+ ./configure --prefix=/usr
+ make
+ make install
+
+------------------------------------
+
+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 ----

View file

@ -0,0 +1,45 @@
task 1.7.1-1
------------------------------------------
A command-line to do list manager that can be used
with the gtd system.
Runtime requirements:
cygwin-1.5.25 or newer
libncurses
Build requirements:
cygwin-1.5.25 or newer
gcc-3.4.4-1 or newer
libncurses-devel
Canonical homepage:
http://taskwarrior.org
Canonical download:
http://taskwarrior.org/download
License:
GPLv2+
Language:
C++
------------------------------------
Build instructions:
unpack task-1.7.1-1-src.tar.bz2
if you use setup to install this src package,
it will be unpacked under /usr/src automatically
cd /usr/src/task-1.7.1-1
./configure --prefix=/usr
make
make install
------------------------------------
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 ----

View file

@ -0,0 +1,64 @@
Name: task
Version: 1.8.0
Release: 0%{?dist}
Summary: A command-line to do list manager
Group: Applications/Productivity
License: GPLv2+
URL: http://taskwarrior.org
Source0: http://taskwarrior.org/download/%{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: ncurses-devel
%description
Task is a command-line to do list manager. It has
support for GTD functionality and includes the
following features: tags, colorful tabular output,
reports and graphs, lots of manipulation commands,
low-level API, abbreviations for all commands and
options, multiuser file locking, recurring tasks.
%prep
%setup -q
%build
%configure
make %{?_smp_mflags}
%install
rm -rf $RPM_BUILD_ROOT
make install DESTDIR=$RPM_BUILD_ROOT
mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d
install -m 644 -T scripts/bash/task_completion.sh $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d/task
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root,-)
%doc AUTHORS ChangeLog COPYING NEWS README scripts
%{_bindir}/task
%{_mandir}/man1/task.1.gz
%{_mandir}/man5/taskrc.5.gz
%{_mandir}/man5/task-tutorial.5.gz
%{_sysconfdir}/bash_completion.d
%changelog
* Mon Jun 15 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.8.0-0
Intial RPM for task release 1.8.0
Installs now bash_completion file
* Tue Jun 08 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.7.1-2
- Fixed inclusion of manpages.
* Tue Jun 08 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.7.1-1
- Initial RPM for bugfix release 1.7.1.
- Updated references to new project homepage in spec file.
* Tue May 19 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.7.0-2
- Changed license to GPLv2+ and removed Requires macro.
- See https://bugzilla.redhat.com/show_bug.cgi?id=501498
* Tue May 19 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.7.0-1
- Initial RPM.

View file

@ -0,0 +1,24 @@
Thank you for taking a look at task!
Task is a GTD, todo list, task management, command line utility with a multitude
of features. It is a portable, well supported, very active project, and it is
Open Source. Task has binary distributions, online documentation, demonstration
movies, and you'll find all the details at the site:
http://taskwarrior.org
At the site you'll find a wiki, discussion forums, downloads, news and more.
Your contributions are especially welcome. Whether it comes in the form of
code patches, ideas, discussion, bug reports or just encouragement, your input
is needed.
Please send your support questions and code patches to:
support@taskwarrior.org
Consider joining taskwarrior.org and participating in the future of task.
---

View file

@ -0,0 +1 @@
<pkg-contents spec="1.12"><f n="task" o="paul" g="staff" p="33261" pt="/Users/paul/task.git/package-config/osx/binary/task" m="false" t="file"/></pkg-contents>

View file

@ -0,0 +1 @@
<pkgref spec="1.12" uuid="C71026FD-E252-42CD-89C3-2F6F087AAF17"><config><identifier>com.beckingham.task180.task.pkg</identifier><version>1.8.0</version><description></description><post-install type="none"/><requireAuthorization/><installFrom mod="true">/Users/paul/task.git/package-config/osx/binary/task</installFrom><installTo mod="true" relocatable="true">/usr/local/bin</installTo><flags><followSymbolicLinks/></flags><packageStore type="internal"></packageStore><mod>parent</mod><mod>locationType</mod><mod>relocatable</mod><mod>version</mod><mod>installTo.path</mod><mod>installTo</mod></config><contents><file-list>01task-contents.xml</file-list><filter>/CVS$</filter><filter>/\.svn$</filter><filter>/\.cvsignore$</filter><filter>/\.cvspass$</filter><filter>/\.DS_Store$</filter></contents></pkgref>

View file

@ -0,0 +1 @@
<pkmkdoc spec="1.12"><properties><title>Task 1.8.0</title><build>/Users/paul/Desktop/task-1.8.0.pkg</build><organization>com.beckingham</organization><userSees ui="easy"/><min-target os="3"/><domain anywhere="true" system="true"/></properties><distribution><versions min-spec="1.000000"/><scripts></scripts></distribution><contents><choice title="task" id="choice0" starts_selected="true" starts_enabled="true" starts_hidden="false"><pkgref id="com.beckingham.task180.task.pkg"/><choice-reqs><requirement id="tosv" operator="ge" value="'10.5.0'" selected="no" enabled="no" hidden="unchanged" startSelected="unchanged" startEnabled="unchanged" startHidden="unchanged"/></choice-reqs></choice></contents><resources bg-scale="proportional" bg-align="center"><locale lang="en"><resource mod="true" type="license">/Users/paul/task.git/package-config/osx/binary/COPYING.txt</resource><resource mod="true" type="readme">/Users/paul/task.git/package-config/osx/binary/README.txt</resource></locale></resources><flags/><item type="file">01task.xml</item><mod>properties.title</mod><mod>properties.anywhereDomain</mod><mod>properties.systemDomain</mod></pkmkdoc>

View file

@ -0,0 +1,22 @@
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
task (1.7.1-0ubuntu1) jaunty; urgency=low
* Initial deb package for bugfix release 1.7.1
* Updated references to new project homepage in control file.
* dpatch not longer neededas upstream version contains fix
for taskrc.5 bug
-- Federico Hernandez <ultrafredde@gmail.com> Tue, 09 Jun 2009 11:49:51 +0200
task (1.7.0-0ubuntu1) jaunty; urgency=low
* Initial release (LP: #378847)
* Fixed bug in taskrc.5 man page from upstream project
which made lintian complain
-- Federico Hernandez <ultrafredde@gmail.com> Wed, 27 May 2009 23:57:08 +0200

View file

@ -0,0 +1 @@
7

View file

@ -0,0 +1,19 @@
Source: task
Section: utils
Priority: optional
Maintainer: Federico Hernandez <ultrafredde@gmail.com>
XSBC-Original-Maintainer: Federico Hernandez <ultrafredde@gmail.com>
Build-Depends: debhelper (>= 7), autotools-dev, libncurses5-dev
Standards-Version: 3.8.0.1
Homepage: http://taskwarrior.org
Package: task
Architecture: any
Depends: ${shlibs:Depends}
Description: A command-line to do list manager
Task is a command-line to do list manager. It has
support for GTD functionality and includes the
following features: tags, colorful tabular output,
reports and graphs, lots of manipulation commands,
low-level API, abbreviations for all commands and
options, multiuser file locking, recurring tasks.

View file

@ -0,0 +1,56 @@
This package was debianized by:
Federico Hernandez <ultrafredde@gmail.com> on Thu, 11 Jun 2009 23:02:28 +0200
It was downloaded from:
http://taskwarrior.org
Upstream Authors:
Paul Beckingham <paul@beckingham.net>
Damian Glenny
Andy Lester
H. İbrahim Güngör
Stefan Dorn
Michael Greb
Benjamin Tegarden
Chris Pride
Richard Querin
Federico Hernandez
T. Charles Yun
David J Patrick
P.C. Shyamshankar
Johan Friis
Steven de Brouwer
Copyright:
Copyright 2006 - 2009, Paul Beckingham
Copyright 2009 Federico Hernandez
Copyright 2009 P.C. Shyamshankar
License:
This package 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 package 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 package; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
On Debian systems, the complete text of the GNU General
Public License can be found in `/usr/share/common-licenses/GPL-2'.
The Debian packaging is:
Copyright (C) 2009, Federico Hernandez <ultrafredde@gmail.com>
and is licensed under the GPL, see above.

View file

@ -0,0 +1,3 @@
AUTHORS
NEWS
README

View file

@ -0,0 +1,46 @@
#!/usr/bin/make -f
config.status: configure
dh_testdir
./configure $(CROSS) --prefix=/usr --docdir=$(DATADIR)/doc/task
build: build-stamp
build-stamp: config.status
dh_testdir
$(MAKE)
touch $@
clean:
dh_testdir
dh_testroot
[ ! -f Makefile ] || $(MAKE) distclean
dh_clean
install: build
dh_testdir
dh_testroot
dh_prep
$(MAKE) DESTDIR=$(CURDIR)/debian/task install
binary-indep: install
binary-arch: install
dh_testdir
dh_testroot
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_strip
dh_compress
dh_fixperms
dh_installdeb
dh_shlibdeps
dh_gencontrol
dh_md5sums
dh_builddeb
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install

View file

@ -0,0 +1,3 @@
version=3
http://taskwarrior.org/download/task-(.*)\.tar\.gz

View file

@ -27,6 +27,7 @@
# The routines will do completion of: # The routines will do completion of:
# #
# *) task subcommands # *) task subcommands
# *) project names
# *) tag names # *) tag names
# #
# To use these routines: # To use these routines:
@ -47,6 +48,18 @@
# http://taskwarrior.org # http://taskwarrior.org
# #
_task_get_projects() {
task _projects
}
_task_get_tags() {
task _tags
}
_task_get_config() {
task _config
}
_task() _task()
{ {
local cur prev opts base local cur prev opts base
@ -55,15 +68,29 @@ _task()
cur="${COMP_WORDS[COMP_CWORD]}" cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}" prev="${COMP_WORDS[COMP_CWORD-1]}"
opts="active add annotate append calendar color completed delete done duplicate edit export ghistory help history import info list long ls newest next oldest overdue projects start stats stop summary tags timesheet undelete undo version" opts="$(task _commands) $(task _ids)"
case "${prev}" in case "${cur}" in
ls|list|long) pro*:*)
if [[ ${cur} == +* ]] ; then local projects=$(_task_get_projects)
local tags=$( task tags | egrep -v 'tags|^$'|sed 's/^/+/' ) local partial_project="${cur/*:/}"
COMPREPLY=( $(compgen -W "${projects}" -- ${partial_project}) )
return 0
;;
+*)
local tags=$(_task_get_tags | sed 's/^/+/')
COMPREPLY=( $(compgen -W "${tags}" -- ${cur}) ) COMPREPLY=( $(compgen -W "${tags}" -- ${cur}) )
return 0 return 0
fi ;;
-*)
local tags=$(_task_get_tags | sed 's/^/-/')
COMPREPLY=( $(compgen -W "${tags}" -- ${cur}) )
return 0
;;
rc.*)
local config=$(_task_get_config | sed 's/^/rc\./')
COMPREPLY=( $(compgen -W "${config}" -- ${cur}) )
return 0
;; ;;
esac esac

57
scripts/vim/README Normal file
View file

@ -0,0 +1,57 @@
Configure VIM for Syntax Highlighting of Task Data
The task data files (pending.data, completed.data and undo.data) as well as
edits made via commands like "task 1 edit" can be color-highlighted if you
happen to use VIM as your preferred text editor. Eventually this will happen
automatically in newer versions of VIM, but for now you have to do a little
bit of file shuffling.
Prerequisites
For this to work, you need to first have syntax highlighting enabled when you
use VIM. This happens to be the default for most VIM installations, but it is
usually quite simple if that doesn't happen to be so in your case. Rather than
repeat the excellent VIM documentation here, please see the appropriate VIM
documentation itself. Generally this can be made seen by starting vim/gvim and
issuing the following command:
:help syntax
You may prefer instead to read the help online at:
http://vimdoc.sourceforge.net/htmldoc/syntax.html#syntax
Configuring VIM to Understand Task Data
Once you have VIM's syntax highlighting enabled and working with other file
types properly, configuring it for use with task is simple. You simply need to
copy some files that came with task into your home directory so that you have:
~/.vim/ftdetect/task.vim
~/.vim/syntax/taskdata.vim
~/.vim/syntax/taskedit.vim
The source of these files varies depending on how you installed task. If you
installed task via a regular package (rpm or deb) you can find these files in
/usr/share/doc/task-VERSION/scripts/vim/. If you built task yourself from the
tarball (using the default configure options), these will be in
/usr/local/share/doc/task-VERSION/scripts/vim/ instead. So you should be able
to do one of the following:
cp -av /usr/share/doc/task-VERSION/scripts/vim/* ~/.vim/
or
cp -av /usr/local/share/doc/task-VERSION/scripts/vim/* ~/.vim/
You should then be ready to go.
---
All three above mentioned files are
Copyright 2009 John Florian
and are available under the GNU Public License version 2 or later.
For the full text of this license, see COPYING.

View file

@ -0,0 +1,18 @@
" Vim support file to detect task data files and single task edits
"
" Maintainer: John Florian <jflorian@doubledog.org>
" Updated: Wed Jul 8 19:45:55 EDT 2009
"
" Copyright 2009 John Florian
"
" This file is available under the GNU Public License version 2 or later.
" For the full text of this license, see COPYING.
" for the raw data files
au BufRead,BufNewFile {pending,completed,undo}.data set filetype=taskdata
" for 'task 42 edit'
au BufRead,BufNewFile *.task set filetype=taskedit
" vim:noexpandtab

View file

@ -0,0 +1,48 @@
" Vim syntax file
" Language: task data
" Maintainer: John Florian <jflorian@doubledog.org>
" Updated: Wed Jul 8 19:46:20 EDT 2009
"
" Copyright 2009 John Florian
"
" This file is available under the GNU Public License version 2 or later.
" For the full text of this license, see COPYING.
" For version 5.x: Clear all syntax items.
" For version 6.x: Quit when a syntax file was already loaded.
if version < 600
syntax clear
elseif exists("b:current_syntax")
finish
endif
" Key Names for values.
syn keyword taskdataKey description due end entry imask mask parent
syn keyword taskdataKey priority project recur start status tags uuid
syn match taskdataKey "annotation_\d\+"
syn match taskdataUndo "^time.*$"
syn match taskdataUndo "^\(old \|new \|---\)"
" Values associated with key names.
"
" Strings
syn region taskdataString matchgroup=Normal start=+"+ end=+"+
\ contains=taskdataEncoded,taskdataUUID,@Spell
"
" Special Embedded Characters (e.g., "&comma;")
syn match taskdataEncoded "&\a\+;" contained
" UUIDs
syn match taskdataUUID "\x\{8}-\(\x\{4}-\)\{3}\x\{12}" contained
" The default methods for highlighting. Can be overridden later.
hi def link taskdataEncoded Function
hi def link taskdataKey Statement
hi def link taskdataString String
hi def link taskdataUUID Special
hi def link taskdataUndo Type
let b:current_syntax = "taskdata"
" vim:noexpandtab

View file

@ -0,0 +1,40 @@
" Vim syntax file
" Language: support for 'task 42 edit'
" Maintainer: John Florian <jflorian@doubledog.org>
" Updated: Wed Jul 8 19:46:32 EDT 2009
"
" Copyright 2009 John Florian
"
" This file is available under the GNU Public License version 2 or later.
" For the full text of this license, see COPYING.
" For version 5.x: Clear all syntax items.
" For version 6.x: Quit when a syntax file was already loaded.
if version < 600
syntax clear
elseif exists("b:current_syntax")
finish
endif
syn match taskeditHeading "^\s*#\s*Name\s\+Editable details\s*$" contained
syn match taskeditHeading "^\s*#\s*-\+\s\+-\+\s*$" contained
syn match taskeditReadOnly "^\s*#\s*\(UU\)\?ID:.*$" contained
syn match taskeditReadOnly "^\s*#\s*Status:.*$" contained
syn match taskeditReadOnly "^\s*#\s*i\?Mask:.*$" contained
syn match taskeditKey "^ *.\{-}:" nextgroup=taskeditString
syn match taskeditComment "^\s*#.*$"
\ contains=taskeditReadOnly,taskeditHeading
syn match taskeditString ".*$" contained contains=@Spell
" The default methods for highlighting. Can be overridden later.
hi def link taskeditComment Comment
hi def link taskeditHeading Function
hi def link taskeditKey Statement
hi def link taskeditReadOnly Special
hi def link taskeditString String
let b:current_syntax = "taskedit"
" vim:noexpandtab

58
scripts/zsh/_task Normal file
View file

@ -0,0 +1,58 @@
#compdef task
# zsh completion for task
#
# Copyright 2009 P.C. Shyamshankar
# All rights reserved.
#
# This script is part of the task project.
#
# 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
#
typeset -g _task_cmds
_task_cmds=($(task rubbish-command | sed -n -e 's/^\s\+task \(\w\+\) .*/\1/p' | grep -v ID))
# As of task 1.7.0,
# _task_cmds=(add append annotate completed edit duplicate delete undelete info start stop done undo projects tags summary timesheet history ghistory next calendar active overdue stats import export color version help list long ls newest oldest)
_task() {
_arguments -s -S \
"*::task command:_task_commands"
return 0
}
(( $+functions[_task_commands] )) ||
_task_commands() {
local cmd ret=1
if (( CURRENT == 1 )); then
_describe -t commands 'task command' _task_cmds
else
local curcontext="${curcontext}"
cmd="${_task_cmds[(r)$words[1]:*]%%:*}"
if (( $#cmd )); then
curcontext="${curcontext%:*:*}:task-${cmd}"
_call_function ret _task_${cmd} || _message "No command remaining."
else
_message "Unknown subcommand ${cmd}"
fi
return ret
fi
}

761
src/Att.cpp Normal file
View file

@ -0,0 +1,761 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include "text.h"
#include "color.h"
#include "util.h"
#include "Date.h"
#include "Duration.h"
#include "Context.h"
#include "Att.h"
extern Context context;
static const char* internalNames[] =
{
"entry",
"start",
"end",
"parent",
"uuid",
"mask",
"imask",
"limit",
"status",
"description",
};
static const char* modifiableNames[] =
{
"project",
"priority",
"fg",
"bg",
"due",
"recur",
"until",
"wait",
};
// Synonyms on the same line.
static const char* modifierNames[] =
{
"before", "under", "below",
"after", "over", "above",
"none",
"any",
"is", "equals",
"isnt", "not",
"has", "contains",
"hasnt",
"startswith", "left",
"endswith", "right",
};
#define NUM_INTERNAL_NAMES (sizeof (internalNames) / sizeof (internalNames[0]))
#define NUM_MODIFIABLE_NAMES (sizeof (modifiableNames) / sizeof (modifiableNames[0]))
#define NUM_MODIFIER_NAMES (sizeof (modifierNames) / sizeof (modifierNames[0]))
////////////////////////////////////////////////////////////////////////////////
Att::Att ()
: mName ("")
, mValue ("")
, mMod ("")
{
}
////////////////////////////////////////////////////////////////////////////////
Att::Att (const std::string& name, const std::string& mod, const std::string& value)
{
mName = name;
mValue = value;
mMod = mod;
}
////////////////////////////////////////////////////////////////////////////////
Att::Att (const std::string& name, const std::string& mod, int value)
{
mName = name;
std::stringstream s;
s << value;
mValue = s.str ();
mMod = mod;
}
////////////////////////////////////////////////////////////////////////////////
Att::Att (const std::string& name, const std::string& value)
{
mName = name;
mValue = value;
mMod = "";
}
////////////////////////////////////////////////////////////////////////////////
Att::Att (const std::string& name, int value)
{
mName = name;
std::stringstream s;
s << value;
mValue = s.str ();
mMod = "";
}
////////////////////////////////////////////////////////////////////////////////
Att::Att (const Att& other)
{
mName = other.mName;
mValue = other.mValue;
mMod = other.mMod;
}
////////////////////////////////////////////////////////////////////////////////
Att& Att::operator= (const Att& other)
{
if (this != &other)
{
mName = other.mName;
mValue = other.mValue;
mMod = other.mMod;
}
return *this;
}
////////////////////////////////////////////////////////////////////////////////
Att::~Att ()
{
}
////////////////////////////////////////////////////////////////////////////////
// For parsing.
bool Att::valid (const std::string& input) const
{
Nibbler n (input);
std::string ignored;
if (n.getUntilOneOf (".:", ignored))
{
if (ignored.length () == 0)
return false;
while (n.skip ('.'))
if (!n.getUntilOneOf (".:", ignored))
return false;
if (n.skip (':') &&
(n.getQuoted ('"', ignored) ||
n.getUntil (' ', ignored) ||
n.getUntilEOS (ignored) ||
n.depleted ()))
return true;
return false;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool Att::validInternalName (const std::string& name)
{
for (unsigned int i = 0; i < NUM_INTERNAL_NAMES; ++i)
if (name == internalNames[i])
return true;
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool Att::validModifiableName (const std::string& name)
{
for (unsigned int i = 0; i < NUM_MODIFIABLE_NAMES; ++i)
if (name == modifiableNames[i])
return true;
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool Att::validNameValue (
const std::string& name,
const std::string& mod,
const std::string& value)
{
std::string writableName = name;
std::string writableMod = mod;
std::string writableValue = value;
return Att::validNameValue (writableName, writableMod, writableValue);
}
////////////////////////////////////////////////////////////////////////////////
bool Att::validNameValue (
std::string& name,
std::string& mod,
std::string& value)
{
// First, guess at the full attribute name.
std::vector <std::string> candidates;
for (unsigned i = 0; i < NUM_INTERNAL_NAMES; ++i)
candidates.push_back (internalNames[i]);
for (unsigned i = 0; i < NUM_MODIFIABLE_NAMES; ++i)
candidates.push_back (modifiableNames[i]);
std::vector <std::string> matches;
autoComplete (name, candidates, matches);
if (matches.size () == 0)
return false;
else if (matches.size () != 1)
{
std::string error = "Ambiguous attribute '" + name + "' - could be either of "; // TODO i18n
std::string combined;
join (combined, ", ", matches);
throw error + combined;
}
name = matches[0];
// Second, guess at the modifier name.
if (mod != "")
{
candidates.clear ();
for (unsigned i = 0; i < NUM_MODIFIER_NAMES; ++i)
candidates.push_back (modifierNames[i]);
matches.clear ();
autoComplete (mod, candidates, matches);
if (matches.size () == 0)
throw std::string ("Unrecognized modifier '") + mod + "'";
else if (matches.size () != 1)
{
std::string error = "Ambiguous modifier '" + mod + "' - could be either of "; // TODO i18n
std::string combined;
join (combined, ", ", matches);
error += combined;
throw error + combined;
}
mod = matches[0];
}
// Some attributes are intended to be private, unless the command is read-
// only, in which cased these are perfectly valid elements of a filter.
if (context.cmd.isWriteCommand () &&
!validModifiableName (name))
throw std::string ("\"") +
name +
"\" is not an attribute you may modify directly.";
// Thirdly, make sure the value has the expected form or values.
if (name == "project")
{
if (!noSpaces (value))
throw std::string ("The '") + name + "' attribute may not contain spaces.";
}
else if (name == "priority")
{
if (value != "")
{
value = upperCase (value);
if (value != "H" &&
value != "M" &&
value != "L")
throw std::string ("\"") +
value +
"\" is not a valid priority. Use H, M, L or leave blank.";
}
}
else if (name == "description")
{
if (context.cmd.isWriteCommand ())
{
if (value == "")
throw std::string ("The '") + name + "' attribute must not be blank.";
if (!noVerticalSpace (value))
throw std::string ("The '") + name + "' attribute must not contain vertical white space.";
}
}
else if (name == "fg" || name == "bg")
{
if (value != "")
Text::guessColor (value);
}
else if (name == "due" ||
name == "until" ||
name == "wait")
{
// Validate and convert to epoch.
if (value != "")
value = Date (value, context.config.get ("dateformat", "m/d/Y")).toEpochString ();
}
else if (name == "recur")
{
// Just validate, don't convert to days.
Duration d;
if (value != "")
d.parse (value);
}
else if (name == "limit")
{
if (value == "" || !digitsOnly (value))
throw std::string ("The '") + name + "' attribute must be an integer.";
}
else if (name == "status")
{
value = lowerCase (value);
std::vector <std::string> matches;
std::vector <std::string> candidates;
candidates.push_back ("pending");
candidates.push_back ("completed");
candidates.push_back ("deleted");
candidates.push_back ("recurring");
candidates.push_back ("waiting");
autoComplete (value, candidates, matches);
if (matches.size () == 1)
value = matches[0];
else
throw std::string ("\"") +
value +
"\" is not a valid status. Use 'pending', 'completed', 'deleted', 'recurring' or 'waiting'.";
}
else if (! validInternalName (name) &&
! validModifiableName (name))
throw std::string ("'") + name + "' is not a recognized attribute.";
return true;
}
////////////////////////////////////////////////////////////////////////////////
// TODO Obsolete
bool Att::validMod (const std::string& mod)
{
for (unsigned int i = 0; i < NUM_MODIFIER_NAMES; ++i)
if (modifierNames[i] == mod)
return true;
return false;
}
////////////////////////////////////////////////////////////////////////////////
// The type of an attribute is useful for modifier evaluation.
std::string Att::type (const std::string& name) const
{
if (name == "due" ||
name == "until" ||
name == "start" ||
name == "entry" ||
name == "end" ||
name == "wait")
return "date";
else if (name == "recur")
return "duration";
else if (name == "limit")
return "number";
else
return "text";
}
////////////////////////////////////////////////////////////////////////////////
//
// start --> name --> . --> mod --> : --> " --> value --> " --> end
// | ^
// |_____________________|
//
void Att::parse (const std::string& input)
{
Nibbler n (input);
parse (n);
}
void Att::parse (Nibbler& n)
{
// Ensure a clean object first.
mName = "";
mValue = "";
mMod = "";
if (n.getUntilOneOf (".:", mName))
{
if (mName.length () == 0)
throw std::string ("Missing attribute name"); // TODO i18n
if (n.skip ('.'))
{
std::string mod;
if (n.getUntil (":", mod))
{
if (validMod (mod))
mMod = mod;
else
throw std::string ("The name '") + mod + "' is not a valid modifier"; // TODO i18n
}
else
throw std::string ("Missing . or : after modifier"); // TODO i18n
}
if (n.skip (':'))
{
// Both quoted and unquoted Att's are accepted.
// Consider removing this for a stricter parse.
if (n.getQuoted ('"', mValue) ||
n.getUntil (' ', mValue))
{
decode (mValue);
}
}
else
throw std::string ("Missing : after attribute name"); // TODO i18n
}
else
throw std::string ("Missing : after attribute name"); // TODO i18n
/* TODO This might be too slow to include. Test.
validNameValue (mName, mMod, mValue);
*/
}
////////////////////////////////////////////////////////////////////////////////
// "this" is the attribute that has modifiers. "other" is the attribute from a
// Record that does not have modifiers, but may have a value.
bool Att::match (const Att& other) const
{
// All matches are assumed to pass, any short-circuit on non-match.
// If there are no mods, just perform a straight compare on value.
if (mMod == "")
{
if (mValue != other.mValue)
return false;
}
// has = contains as a substring.
else if (mMod == "has" || mMod == "contains") // TODO i18n
{
if (other.mValue.find (mValue) == std::string::npos)
return false;
}
// is = equal. Nop.
else if (mMod == "is" || mMod == "equals") // TODO i18n
{
if (mValue != other.mValue)
return false;
}
// isnt = not equal.
else if (mMod == "isnt" || mMod == "not") // TODO i18n
{
if (mValue == other.mValue)
return false;
}
// any = any value, but not empty value.
else if (mMod == "any") // TODO i18n
{
if (other.mValue == "")
return false;
}
// none = must have empty value.
else if (mMod == "none") // TODO i18n
{
if (other.mValue != "")
return false;
}
// startswith = first characters must match.
else if (mMod == "startswith" || mMod == "left") // TODO i18n
{
if (other.mValue.length () < mValue.length ())
return false;
if (mValue != other.mValue.substr (0, mValue.length ()))
return false;
}
// endswith = last characters must match.
else if (mMod == "endswith" || mMod == "right") // TODO i18n
{
if (other.mValue.length () < mValue.length ())
return false;
if (mValue != other.mValue.substr (
other.mValue.length () - mValue.length (),
std::string::npos))
return false;
}
// hasnt = does not contain as a substring.
else if (mMod == "hasnt") // TODO i18n
{
if (other.mValue.find (mValue) != std::string::npos)
return false;
}
// before = under = below = <
else if (mMod == "before" || mMod == "under" || mMod == "below")
{
std::string which = type (mName);
if (which == "duration")
{
Duration literal (mValue);
Duration variable ((time_t)::atoi (other.mValue.c_str ()));
if (!(variable < literal))
return false;
}
else if (which == "date")
{
Date literal (mValue.c_str (), context.config.get ("dateformat", "m/d/Y"));
Date variable ((time_t)::atoi (other.mValue.c_str ()));
if (other.mValue == "" || ! (variable < literal))
return false;
}
else if (which == "number")
{
if (::atoi (mValue.c_str ()) >= ::atoi (other.mValue.c_str ()))
return false;
}
else if (which == "text")
{
if (mValue <= other.mValue)
return false;
}
}
// after = over = above = >
else if (mMod == "after" || mMod == "over" || mMod == "above")
{
std::string which = type (mName);
if (which == "duration")
{
Duration literal (mValue);
Duration variable ((time_t)::atoi (other.mValue.c_str ()));
if (! (variable > literal))
return false;
}
else if (which == "date")
{
Date literal (mValue.c_str (), context.config.get ("dateformat", "m/d/Y"));
Date variable ((time_t)::atoi (other.mValue.c_str ()));
if (! (variable > literal))
return false;
}
else if (which == "number")
{
if (::atoi (mValue.c_str ()) <= ::atoi (other.mValue.c_str ()))
return false;
}
else if (which == "text")
{
if (mValue >= other.mValue)
return false;
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
// name : " value "
std::string Att::composeF4 () const
{
std::string output = "";
if (mName != "" && mValue != "")
{
std::string value = mValue;
encode (value);
enquote (value);
output += mName + ":" + value;
}
return output;
}
////////////////////////////////////////////////////////////////////////////////
void Att::mod (const std::string& input)
{
if (input != "" && !validMod (input))
throw std::string ("The name '") + input + "' is not a valid modifier"; // TODO i18n
mMod = input;
}
////////////////////////////////////////////////////////////////////////////////
std::string Att::mod () const
{
return mMod;
}
////////////////////////////////////////////////////////////////////////////////
std::string Att::name () const
{
return mName;
}
////////////////////////////////////////////////////////////////////////////////
void Att::name (const std::string& name)
{
mName = name;
}
////////////////////////////////////////////////////////////////////////////////
std::string Att::value () const
{
return mValue;
}
////////////////////////////////////////////////////////////////////////////////
void Att::value (const std::string& value)
{
mValue = value;
}
////////////////////////////////////////////////////////////////////////////////
int Att::value_int () const
{
return ::atoi (mValue.c_str ());
}
////////////////////////////////////////////////////////////////////////////////
void Att::value_int (int value)
{
std::stringstream s;
s << value;
mValue = s.str ();
}
////////////////////////////////////////////////////////////////////////////////
// Add quotes.
void Att::enquote (std::string& value) const
{
value = '"' + value + '"';
}
////////////////////////////////////////////////////////////////////////////////
// Remove quotes. Instead of being picky, just remove them all. There should
// be none within the value, and this will correct for one possible corruption
// that hand-editing the pending.data file could cause.
void Att::dequote (std::string& value) const
{
std::string::size_type quote;
while ((quote = value.find ('"')) != std::string::npos)
value.replace (quote, 1, "");
}
////////////////////////////////////////////////////////////////////////////////
// Encode values prior to serialization.
// \t -> &tab;
// " -> &quot;
// , -> &comma;
// [ -> &open;
// ] -> &close;
// : -> &colon;
void Att::encode (std::string& value) const
{
std::string::size_type i;
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, "&quot;"); // no i18n
while ((i = value.find (',')) != std::string::npos)
value.replace (i, 1, "&comma;"); // no i18n
while ((i = value.find ('[')) != std::string::npos)
value.replace (i, 1, "&open;"); // no i18n
while ((i = value.find (']')) != std::string::npos)
value.replace (i, 1, "&close;"); // no i18n
while ((i = value.find (':')) != std::string::npos)
value.replace (i, 1, "&colon;"); // no i18n
}
////////////////////////////////////////////////////////////////////////////////
// Decode values after parse.
// \t <- &tab;
// " <- &quot;
// , <- &comma;
// [ <- &open;
// ] <- &close;
// : <- &colon;
void Att::decode (std::string& value) const
{
std::string::size_type i;
while ((i = value.find ("&tab;")) != std::string::npos) // no i18n
value.replace (i, 5, "\t");
while ((i = value.find ("&quot;")) != std::string::npos) // no i18n
value.replace (i, 6, "\"");
while ((i = value.find ("&comma;")) != std::string::npos) // no i18n
value.replace (i, 7, ",");
while ((i = value.find ("&open;")) != std::string::npos) // no i18n
value.replace (i, 6, "[");
while ((i = value.find ("&close;")) != std::string::npos) // no i18n
value.replace (i, 7, "]");
while ((i = value.find ("&colon;")) != std::string::npos) // no i18n
value.replace (i, 7, ":");
}
////////////////////////////////////////////////////////////////////////////////

84
src/Att.h Normal file
View file

@ -0,0 +1,84 @@
////////////////////////////////////////////////////////////////////////////////
// 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_ATT
#define INCLUDED_ATT
#include <string>
#include <vector>
#include "Nibbler.h"
class Att
{
public:
Att ();
Att (const std::string&, const std::string&, const std::string&);
Att (const std::string&, const std::string&, int);
Att (const std::string&, const std::string&);
Att (const std::string&, int);
Att (const Att&);
Att& operator= (const Att&);
~Att ();
bool valid (const std::string&) const;
static bool validInternalName (const std::string&);
static bool validModifiableName (const std::string&);
static bool validNameValue (const std::string&, const std::string&, const std::string&);
static bool validNameValue (std::string&, std::string&, std::string&);
static bool validMod (const std::string&);
std::string type (const std::string&) const;
void parse (const std::string&);
void parse (Nibbler&);
bool match (const Att&) const;
std::string composeF4 () const;
void mod (const std::string&);
std::string mod () const;
std::string name () const;
void name (const std::string&);
std::string value () const;
void value (const std::string&);
int value_int () const;
void value_int (int);
private:
void enquote (std::string&) const;
void dequote (std::string&) const;
void encode (std::string&) const;
void decode (std::string&) const;
private:
std::string mName;
std::string mValue;
std::string mMod;
};
#endif
////////////////////////////////////////////////////////////////////////////////

234
src/Cmd.cpp Normal file
View file

@ -0,0 +1,234 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#include <algorithm>
#include "Cmd.h"
#include "Context.h"
#include "util.h"
#include "text.h"
#include "i18n.h"
#include "main.h"
extern Context context;
////////////////////////////////////////////////////////////////////////////////
Cmd::Cmd ()
: command ("")
{
}
////////////////////////////////////////////////////////////////////////////////
Cmd::Cmd (const std::string& input)
{
parse (input);
}
////////////////////////////////////////////////////////////////////////////////
Cmd::~Cmd ()
{
}
////////////////////////////////////////////////////////////////////////////////
// Determines whether the string represents a unique command name or custom
// report name.
bool Cmd::valid (const std::string& input)
{
load ();
std::vector <std::string> matches;
autoComplete (lowerCase (context.canonicalize (input)), commands, matches);
return matches.size () == 1 ? true : false;
}
////////////////////////////////////////////////////////////////////////////////
// Determines whether the string represents a valid custom report name.
bool Cmd::validCustom (const std::string& input)
{
load ();
std::vector <std::string> matches;
autoComplete (lowerCase (context.canonicalize (input)), customReports, matches);
return matches.size () == 1 ? true : false;
}
////////////////////////////////////////////////////////////////////////////////
void Cmd::parse (const std::string& input)
{
load ();
std::string candidate = lowerCase (context.canonicalize (input));
std::vector <std::string> matches;
autoComplete (candidate, commands, matches);
if (1 == matches.size ())
command = matches[0];
else if (0 == matches.size ())
command = "";
else
{
std::string error = "Ambiguous command '" + candidate + "' - could be either of "; // TODO i18n
std::string combined;
join (combined, ", ", matches);
throw error + combined;
}
}
////////////////////////////////////////////////////////////////////////////////
void Cmd::load ()
{
if (commands.size () == 0)
{
commands.push_back ("_projects");
commands.push_back ("_tags");
commands.push_back ("_commands");
commands.push_back ("_ids");
commands.push_back ("_config");
commands.push_back (context.stringtable.get (CMD_ADD, "add"));
commands.push_back (context.stringtable.get (CMD_APPEND, "append"));
commands.push_back (context.stringtable.get (CMD_ANNOTATE, "annotate"));
commands.push_back (context.stringtable.get (CMD_CALENDAR, "calendar"));
commands.push_back (context.stringtable.get (CMD_COLORS, "colors"));
commands.push_back (context.stringtable.get (CMD_DELETE, "delete"));
commands.push_back (context.stringtable.get (CMD_DONE, "done"));
commands.push_back (context.stringtable.get (CMD_DUPLICATE, "duplicate"));
commands.push_back (context.stringtable.get (CMD_EDIT, "edit"));
commands.push_back (context.stringtable.get (CMD_EXPORT, "export"));
commands.push_back (context.stringtable.get (CMD_HELP, "help"));
commands.push_back (context.stringtable.get (CMD_HISTORY, "history"));
commands.push_back (context.stringtable.get (CMD_GHISTORY, "ghistory"));
commands.push_back (context.stringtable.get (CMD_IMPORT, "import"));
commands.push_back (context.stringtable.get (CMD_INFO, "info"));
commands.push_back (context.stringtable.get (CMD_PROJECTS, "projects"));
#ifdef FEATURE_SHELL
commands.push_back (context.stringtable.get (CMD_SHELL, "shell"));
#endif
commands.push_back (context.stringtable.get (CMD_START, "start"));
commands.push_back (context.stringtable.get (CMD_STATS, "stats"));
commands.push_back (context.stringtable.get (CMD_STOP, "stop"));
commands.push_back (context.stringtable.get (CMD_SUMMARY, "summary"));
commands.push_back (context.stringtable.get (CMD_TAGS, "tags"));
commands.push_back (context.stringtable.get (CMD_TIMESHEET, "timesheet"));
commands.push_back (context.stringtable.get (CMD_UNDO, "undo"));
commands.push_back (context.stringtable.get (CMD_VERSION, "version"));
// Now load the custom reports.
std::vector <std::string> all;
context.config.all (all);
foreach (i, all)
{
if (i->substr (0, 7) == "report.")
{
std::string report = i->substr (7, std::string::npos);
std::string::size_type columns = report.find (".columns");
if (columns != std::string::npos)
{
report = report.substr (0, columns);
// Make sure a custom report does not clash with a built-in
// command.
if (std::find (commands.begin (), commands.end (), report) != commands.end ())
throw std::string ("Custom report '") + report +
"' conflicts with built-in task command.";
// A custom report is also a command.
customReports.push_back (report);
commands.push_back (report);
}
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
void Cmd::allCustomReports (std::vector <std::string>& all) const
{
all = customReports;
}
////////////////////////////////////////////////////////////////////////////////
void Cmd::allCommands (std::vector <std::string>& all) const
{
all.clear ();
foreach (command, commands)
if (command->substr (0, 1) != "_")
all.push_back (*command);
}
////////////////////////////////////////////////////////////////////////////////
// Commands that do not directly modify the data files.
bool Cmd::isReadOnlyCommand ()
{
if (command == "_projects" ||
command == "_tags" ||
command == "_commands" ||
command == "_ids" ||
command == "_config" ||
command == context.stringtable.get (CMD_CALENDAR, "calendar") ||
command == context.stringtable.get (CMD_COLORS, "colors") ||
command == context.stringtable.get (CMD_EXPORT, "export") ||
command == context.stringtable.get (CMD_HELP, "help") ||
command == context.stringtable.get (CMD_HISTORY, "history") ||
command == context.stringtable.get (CMD_GHISTORY, "ghistory") ||
command == context.stringtable.get (CMD_INFO, "info") ||
command == context.stringtable.get (CMD_PROJECTS, "projects") ||
command == context.stringtable.get (CMD_SHELL, "shell") ||
command == context.stringtable.get (CMD_STATS, "stats") ||
command == context.stringtable.get (CMD_SUMMARY, "summary") ||
command == context.stringtable.get (CMD_TAGS, "tags") ||
command == context.stringtable.get (CMD_TIMESHEET, "timesheet") ||
command == context.stringtable.get (CMD_VERSION, "version") ||
validCustom (command))
return true;
return false;
}
////////////////////////////////////////////////////////////////////////////////
// Commands that directly modify the data files.
bool Cmd::isWriteCommand ()
{
if (command == context.stringtable.get (CMD_ADD, "add") ||
command == context.stringtable.get (CMD_APPEND, "append") ||
command == context.stringtable.get (CMD_ANNOTATE, "annotate") ||
command == context.stringtable.get (CMD_DELETE, "delete") ||
command == context.stringtable.get (CMD_DONE, "done") ||
command == context.stringtable.get (CMD_DUPLICATE, "duplicate") ||
command == context.stringtable.get (CMD_EDIT, "edit") ||
command == context.stringtable.get (CMD_IMPORT, "import") ||
command == context.stringtable.get (CMD_START, "start") ||
command == context.stringtable.get (CMD_STOP, "stop") ||
command == context.stringtable.get (CMD_UNDO, "undo"))
return true;
return false;
}
////////////////////////////////////////////////////////////////////////////////

64
src/Cmd.h Normal file
View file

@ -0,0 +1,64 @@
////////////////////////////////////////////////////////////////////////////////
// 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_CMD
#define INCLUDED_CMD
#include <vector>
#include <string>
class Cmd
{
public:
Cmd (); // Default constructor
Cmd (const std::string&); // Default constructor
~Cmd (); // Destructor
Cmd (const Cmd&);
Cmd& operator= (const Cmd&);
bool valid (const std::string&);
bool validCustom (const std::string&);
void parse (const std::string&);
void allCustomReports (std::vector <std::string>&) const;
void allCommands (std::vector <std::string>&) const;
bool isReadOnlyCommand ();
bool isWriteCommand ();
public:
std::string command;
private:
void load ();
private:
std::vector <std::string> commands;
std::vector <std::string> customReports;
};
#endif
////////////////////////////////////////////////////////////////////////////////

View file

@ -32,8 +32,9 @@
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <pwd.h> #include <pwd.h>
#include "task.h"
#include "Config.h" #include "Config.h"
#include "text.h"
#include "util.h"
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// These are default (but overridable) reports. These entries are necessary // These are default (but overridable) reports. These entries are necessary
@ -44,32 +45,7 @@
// upgrade program to make the change, or c) this. // upgrade program to make the change, or c) this.
Config::Config () Config::Config ()
{ {
(*this)["report.long.description"] = "Lists all task, all data, matching the specified criteria"; setDefaults ();
(*this)["report.long.columns"] = "id,project,priority,entry,start,due,recur,age,tags,description";
(*this)["report.long.labels"] = "ID,Project,Pri,Added,Started,Due,Recur,Age,Tags,Description";
(*this)["report.long.sort"] = "due+,priority-,project+";
(*this)["report.list.description"] = "Lists all tasks matching the specified criteria";
(*this)["report.list.columns"] = "id,project,priority,due,active,age,description";
(*this)["report.list.labels"] = "ID,Project,Pri,Due,Active,Age,Description";
(*this)["report.list.sort"] = "due+,priority-,project+";
(*this)["report.ls.description"] = "Minimal listing of all tasks matching the specified criteria";
(*this)["report.ls.columns"] = "id,project,priority,description";
(*this)["report.ls.labels"] = "ID,Project,Pri,Description";
(*this)["report.ls.sort"] = "priority-,project+";
(*this)["report.newest.description"] = "Shows the newest tasks";
(*this)["report.newest.columns"] = "id,project,priority,due,active,age,description";
(*this)["report.newest.labels"] = "ID,Project,Pri,Due,Active,Age,Description";
(*this)["report.newest.sort"] = "id-";
(*this)["report.newest.limit"] = "10";
(*this)["report.oldest.description"] = "Shows the oldest tasks";
(*this)["report.oldest.columns"] = "id,project,priority,due,active,age,description";
(*this)["report.oldest.labels"] = "ID,Project,Pri,Due,Active,Age,Description";
(*this)["report.oldest.sort"] = "id+";
(*this)["report.oldest.limit"] = "10";
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -92,20 +68,20 @@ bool Config::load (const std::string& file)
while (getline (in, line)) while (getline (in, line))
{ {
// Remove comments. // Remove comments.
size_type pound = line.find ("#"); std::string::size_type pound = line.find ("#"); // no i18n
if (pound != std::string::npos) if (pound != std::string::npos)
line = line.substr (0, pound); line = line.substr (0, pound);
line = trim (line, " \t"); line = trim (line, " \t"); // no i18n
// Skip empty lines. // Skip empty lines.
if (line.length () > 0) if (line.length () > 0)
{ {
size_type equal = line.find ("="); std::string::size_type equal = line.find ("="); // no i18n
if (equal != std::string::npos) if (equal != std::string::npos)
{ {
std::string key = trim (line.substr (0, equal), " \t"); std::string key = trim (line.substr (0, equal), " \t"); // no i18n
std::string value = trim (line.substr (equal+1, line.length () - equal), " \t"); std::string value = trim (line.substr (equal+1, line.length () - equal), " \t"); // no i18n
(*this)[key] = value; (*this)[key] = value;
} }
} }
@ -119,112 +95,234 @@ bool Config::load (const std::string& file)
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void Config::createDefault (const std::string& home) void Config::createDefaultRC (const std::string& rc, const std::string& data)
{ {
// Strip trailing slash off home directory, if necessary.
std::string terminatedHome = home;
if (home[home.length () - 1] == '/')
terminatedHome = home.substr (0, home.length () - 1);
// Determine default names of init file and task directory.
std::string rcFile = terminatedHome + "/.taskrc";
std::string dataDir = terminatedHome + "/.task";;
// If rcFile is not found, offer to create one.
if (-1 == access (rcFile.c_str (), F_OK))
{
if (confirm (
"A configuration file could not be found in "
+ rcFile
+ "\n\n"
+ "Would you like a sample .taskrc created, so task can proceed?"))
{
// Create a sample .taskrc file. // Create a sample .taskrc file.
FILE* out; std::stringstream contents;
if ((out = fopen (rcFile.c_str (), "w"))) contents << "# Task program configuration file.\n"
{ << "# For more documentation, see http://taskwarrior.org\n"
fprintf (out, "data.location=%s\n", dataDir.c_str ()); << "\n"
fprintf (out, "confirmation=yes\n"); << "# Files\n"
fprintf (out, "echo.command=yes\n"); << "data.location=" << data << "\n"
fprintf (out, "next=2\n"); << "locking=on # Use file-level locking\n"
fprintf (out, "dateformat=m/d/Y\n"); << "\n"
fprintf (out, "#monthsperline=2\n"); << "# Terminal\n"
fprintf (out, "#defaultwidth=80\n"); << "curses=on # Use ncurses library to determine terminal width\n"
fprintf (out, "curses=on\n"); << "#defaultwidth=80 # Without ncurses, assumed width\n"
fprintf (out, "color=on\n"); << "#editor=vi # Preferred text editor\n"
fprintf (out, "due=7\n"); << "\n"
fprintf (out, "nag=You have higher priority tasks.\n"); << "# Miscellaneous\n"
fprintf (out, "locking=on\n"); << "confirmation=yes # Confirmation on delete, big changes\n"
fprintf (out, "#editor=vi\n"); << "echo.command=yes # Details on command just run\n"
<< "next=2 # How many tasks per project in next report\n"
<< "bulk=2 # > 2 tasks considered 'a lot', for confirmation\n"
<< "nag=You have higher priority tasks. # Nag message to keep you honest\n"
<< "\n"
<< "# Dates\n"
<< "dateformat=m/d/Y # Preferred input and display date format\n"
<< "weekstart=Sunday # Sunday or Monday only\n"
<< "displayweeknumber=yes # Show week numbers on calendar\n"
<< "due=7 # Task is considered due in 7 days\n"
<< "#monthsperline=2 # Number of calendar months on a line\n"
<< "\n"
<< "# Color controls.\n"
<< "color=on # Use color\n"
<< "color.overdue=bold_red # Color of overdue tasks\n"
<< "color.due=bold_yellow # Color of due tasks\n"
<< "color.pri.H=bold # Color of priority:H tasks\n"
<< "#color.pri.M=on_yellow # Color of priority:M tasks\n"
<< "#color.pri.L=on_green # Color of priority:L tasks\n"
<< "#color.pri.none=white on_blue # Color of priority: tasks\n"
<< "color.active=bold_cyan # Color of active tasks\n"
<< "color.tagged=yellow # Color of tagged tasks\n"
<< "#color.tag.bug=yellow # Color of +bug tasks\n"
<< "#color.project.garden=on_green # Color of project:garden tasks\n"
<< "#color.keyword.car=on_blue # Color of description.contains:car tasks\n"
<< "#color.recurring=on_red # Color of recur.any: tasks\n"
<< "#color.header=bold_green # Color of header messages\n"
<< "#color.footnote=bold_green # Color of footnote messages\n"
<< "\n"
<< "#shadow.file=/tmp/shadow.txt # Location of shadow file\n"
<< "#shadow.command=list # Task command for shadow file\n"
<< "#shadow.notify=on # Footnote when updated\n"
<< "\n"
<< "#default.project=foo # Unless otherwise specified\n"
<< "#default.priority=M # Unless otherwise specified\n"
<< "default.command=list # Unless otherwise specified\n"
<< "\n"
<< "# Fields: id,uuid,project,priority,entry,start,due,recur,recur_ind,age,\n"
<< "# age_compact,active,tags,description,description_only\n"
<< "# Description: This report is ...\n"
<< "# Sort: due+,priority-,project+\n"
<< "# Filter: pro:x pri:H +bug limit:10\n"
<< "\n"
<< "# task long\n"
<< "report.long.description=Lists all task, all data, matching the specified criteria\n"
<< "report.long.columns=id,project,priority,entry,start,due,recur,age,tags,description\n"
<< "report.long.labels=ID,Project,Pri,Added,Started,Due,Recur,Age,Tags,Description\n"
<< "report.long.sort=due+,priority-,project+\n"
<< "report.long.filter=status:pending\n"
<< "\n"
<< "# task list\n"
<< "report.list.description=Lists all tasks matching the specified criteria\n"
<< "report.list.columns=id,project,priority,due,active,age,description\n"
<< "report.list.labels=ID,Project,Pri,Due,Active,Age,Description\n"
<< "report.list.sort=due+,priority-,project+\n"
<< "report.list.filter=status:pending\n"
<< "\n"
<< "# task ls\n"
<< "report.ls.description=Minimal listing of all tasks matching the specified criteria\n"
<< "report.ls.columns=id,project,priority,description\n"
<< "report.ls.labels=ID,Project,Pri,Description\n"
<< "report.ls.sort=priority-,project+\n"
<< "report.ls.filter=status:pending\n"
<< "\n"
<< "# task newest\n"
<< "report.newest.description=Shows the newest tasks\n"
<< "report.newest.columns=id,project,priority,due,active,age,description\n"
<< "report.newest.labels=ID,Project,Pri,Due,Active,Age,Description\n"
<< "report.newest.sort=id-\n"
<< "report.newest.filter=status:pending limit:10\n"
<< "\n"
<< "# task oldest\n"
<< "report.oldest.description=Shows the oldest tasks\n"
<< "report.oldest.columns=id,project,priority,due,active,age,description\n"
<< "report.oldest.labels=ID,Project,Pri,Due,Active,Age,Description\n"
<< "report.oldest.sort=id+\n"
<< "report.oldest.filter=status:pending limit:10\n"
<< "\n"
<< "# task overdue\n"
<< "report.overdue.description=Lists overdue tasks matching the specified criteria\n"
<< "report.overdue.columns=id,project,priority,due,active,age,description\n"
<< "report.overdue.labels=ID,Project,Pri,Due,Active,Age,Description\n"
<< "report.overdue.sort=due+,priority-,project+\n"
<< "report.overdue.filter=status:pending due.before:today\n"
<< "\n"
<< "# task active\n"
<< "report.active.description=Lists active tasks matching the specified criteria\n"
<< "report.active.columns=id,project,priority,due,active,age,description\n"
<< "report.active.labels=ID,Project,Pri,Due,Active,Age,Description\n"
<< "report.active.sort=due+,priority-,project+\n"
<< "report.active.filter=status:pending start.any:\n"
<< "\n"
<< "# task completed\n"
<< "report.completed.description=Lists completed tasks matching the specified criteria\n"
<< "report.completed.columns=end,project,priority,age,description\n"
<< "report.completed.labels=Complete,Project,Pri,Age,Description\n"
<< "report.completed.sort=end+,priority-,project+\n"
<< "report.completed.filter=status:completed\n"
<< "\n"
<< "# task recurring\n"
<< "report.recurring.description=Lists recurring tasks matching the specified criteria\n"
<< "report.recurring.columns=id,project,priority,due,recur,active,age,description\n"
<< "report.recurring.labels=ID,Project,Pri,Due,Recur,Active,Age,Description\n"
<< "report.recurring.sort=due+,priority-,project+\n"
<< "report.recurring.filter=status:pending parent.any:\n"
<< "\n"
<< "# task waiting\n"
<< "report.waiting.description=Lists all waiting tasks matching the specified criteria\n"
<< "report.waiting.columns=id,project,priority,wait,age,description\n"
<< "report.waiting.labels=ID,Project,Pri,Wait,Age,Description\n"
<< "report.waiting.sort=wait+,priority-,project+\n"
<< "report.waiting.filter=status:waiting\n"
<< "\n"
<< "# task all\n"
<< "report.all.description=Lists all tasks matching the specified criteria\n"
<< "report.all.columns=id,project,priority,due,active,age,description\n"
<< "report.all.labels=ID,Project,Pri,Due,Active,Age,Description\n"
<< "report.all.sort=due+,priority-,project+\n"
<< "\n"
<< "# task next\n"
<< "report.next.description=Lists the most urgent tasks\n"
<< "report.next.columns=id,project,priority,due,active,age,description\n"
<< "report.next.labels=ID,Project,Pri,Due,Active,Age,Description\n"
<< "report.next.sort=due+,priority-,project+\n"
<< "report.next.filter=status:pending\n"
<< "\n";
fprintf (out, "color.overdue=bold_red\n"); spit (rc, contents.str ());
fprintf (out, "color.due=bold_yellow\n"); }
fprintf (out, "color.pri.H=bold\n");
fprintf (out, "#color.pri.M=on_yellow\n");
fprintf (out, "#color.pri.L=on_green\n");
fprintf (out, "#color.pri.none=white on_blue\n");
fprintf (out, "color.active=bold_cyan\n");
fprintf (out, "color.tagged=yellow\n");
fprintf (out, "#color.tag.bug=yellow\n");
fprintf (out, "#color.project.garden=on_green\n");
fprintf (out, "#color.keyword.car=on_blue\n");
fprintf (out, "#color.recurring=on_red\n");
fprintf (out, "#shadow.file=%s/shadow.txt\n", dataDir.c_str ());
fprintf (out, "#shadow.command=list\n");
fprintf (out, "#shadow.notify=on\n");
fprintf (out, "#default.project=foo\n");
fprintf (out, "#default.priority=M\n");
fprintf (out, "default.command=list\n");
// Custom reports. ////////////////////////////////////////////////////////////////////////////////
fprintf (out, "# Fields: id,uuid,project,priority,entry,start,due,recur,age,active,tags,description\n"); void Config::createDefaultData (const std::string& data)
fprintf (out, "# description_only\n"); {
fprintf (out, "# Description: This report is ...\n"); if (access (data.c_str (), F_OK))
fprintf (out, "# Sort: due+,priority-,project+\n"); mkdir (data.c_str (), S_IRWXU);
fprintf (out, "# Filter: pro:x pri:H +bug\n"); }
fprintf (out, "# Limit: 10\n");
fprintf (out, "report.long.description=Lists all task, all data, matching the specified criteria\n"); ////////////////////////////////////////////////////////////////////////////////
fprintf (out, "report.long.labels=ID,Project,Pri,Added,Started,Due,Recur,Age,Tags,Description\n"); void Config::setDefaults ()
fprintf (out, "report.long.columns=id,project,priority,entry,start,due,recur,age,tags,description\n"); {
fprintf (out, "report.long.sort=due+,priority-,project+\n"); set ("report.long.description", "Lists all task, all data, matching the specified criteria"); // TODO i18n
set ("report.long.columns", "id,project,priority,entry,start,due,recur,age,tags,description"); // TODO i18n
set ("report.long.labels", "ID,Project,Pri,Added,Started,Due,Recur,Age,Tags,Description"); // TODO i18n
set ("report.long.sort", "due+,priority-,project+"); // TODO i18n
set ("report.long.filter", "status:pending"); // TODO i18n
fprintf (out, "report.list.description=Lists all tasks matching the specified criteria\n"); set ("report.list.description", "Lists all tasks matching the specified criteria"); // TODO i18n
fprintf (out, "report.list.labels=ID,Project,Pri,Due,Active,Age,Description\n"); set ("report.list.columns", "id,project,priority,due,active,age,description"); // TODO i18n
fprintf (out, "report.list.columns=id,project,priority,due,active,age,description\n"); set ("report.list.labels", "ID,Project,Pri,Due,Active,Age,Description"); // TODO i18n
fprintf (out, "report.list.sort=due+,priority-,project+\n"); set ("report.list.sort", "due+,priority-,project+"); // TODO i18n
set ("report.list.filter", "status:pending"); // TODO i18n
fprintf (out, "report.ls.description=Minimal listing of all tasks matching the specified criteria\n"); set ("report.ls.description", "Minimal listing of all tasks matching the specified criteria"); // TODO i18n
fprintf (out, "report.ls.labels=ID,Project,Pri,Description\n"); set ("report.ls.columns", "id,project,priority,description"); // TODO i18n
fprintf (out, "report.ls.columns=id,project,priority,description\n"); set ("report.ls.labels", "ID,Project,Pri,Description"); // TODO i18n
fprintf (out, "report.ls.sort=priority-,project+\n"); set ("report.ls.sort", "priority-,project+"); // TODO i18n
set ("report.ls.filter", "status:pending"); // TODO i18n
fprintf (out, "report.newest.description=Shows the newest tasks\n"); set ("report.newest.description", "Shows the newest tasks"); // TODO i18n
fprintf (out, "report.newest.labels=ID,Project,Pri,Due,Active,Age,Description\n"); set ("report.newest.columns", "id,project,priority,due,active,age,description"); // TODO i18n
fprintf (out, "report.newest.columns=id,project,priority,due,active,age,description\n"); set ("report.newest.labels", "ID,Project,Pri,Due,Active,Age,Description"); // TODO i18n
fprintf (out, "report.newest.sort=id-\n"); set ("report.newest.sort", "id-"); // TODO i18n
fprintf (out, "report.newest.limit=10\n"); set ("report.newest.filter", "status:pending limit:10"); // TODO i18n
fprintf (out, "report.oldest.description=Shows the oldest tasks\n"); set ("report.oldest.description", "Shows the oldest tasks"); // TODO i18n
fprintf (out, "report.oldest.labels=ID,Project,Pri,Due,Active,Age,Description\n"); set ("report.oldest.columns", "id,project,priority,due,active,age,description"); // TODO i18n
fprintf (out, "report.oldest.columns=id,project,priority,due,active,age,description\n"); set ("report.oldest.labels", "ID,Project,Pri,Due,Active,Age,Description"); // TODO i18n
fprintf (out, "report.oldest.sort=id+\n"); set ("report.oldest.sort", "id+"); // TODO i18n
fprintf (out, "report.oldest.limit=10\n"); set ("report.oldest.filter", "status:pending limit:10"); // TODO i18n
fclose (out); set ("report.overdue.description", "Lists overdue tasks matching the specified criteria"); // TODO i18n
set ("report.overdue.columns", "id,project,priority,due,active,age,description"); // TODO i18n
set ("report.overdue.labels", "ID,Project,Pri,Due,Active,Age,Description"); // TODO i18n
set ("report.overdue.sort", "due+,priority-,project+"); // TODO i18n
set ("report.overdue.filter", "status:pending due.before:today"); // TODO i18n
std::cout << "Done." << std::endl; set ("report.active.description", "Lists active tasks matching the specified criteria"); // TODO i18n
} set ("report.active.columns", "id,project,priority,due,active,age,description"); // TODO i18n
} set ("report.active.labels", "ID,Project,Pri,Due,Active,Age,Description"); // TODO i18n
} set ("report.active.sort", "due+,priority-,project+"); // TODO i18n
set ("report.active.filter", "status:pending start.any:"); // TODO i18n
this->load (rcFile); set ("report.completed.description", "Lists completed tasks matching the specified criteria"); // TODO i18n
set ("report.completed.columns", "end,project,priority,age,description"); // TODO i18n
set ("report.completed.labels", "Complete,Project,Pri,Age,Description"); // TODO i18n
set ("report.completed.sort", "end+,priority-,project+"); // TODO i18n
set ("report.completed.filter", "status:completed"); // TODO i18n
// Get the data.location value from the (potentially newly created) .taskrc set ("report.recurring.description", "Lists recurring tasks matching the specified criteria"); // TODO i18n
// file. set ("report.recurring.columns", "id,project,priority,due,recur,active,age,description"); // TODO i18n
dataDir = this->get ("data.location", dataDir); set ("report.recurring.labels", "ID,Project,Pri,Due,Recur,Active,Age,Description"); // TODO i18n
if (-1 == access (dataDir.c_str (), F_OK)) set ("report.recurring.sort", "due+,priority-,project+"); // TODO i18n
mkdir (dataDir.c_str (), S_IRWXU); set ("report.recurring.filter", "status:pending parent.any:"); // TODO i18n
set ("report.waiting.description", "Lists all waiting tasks matching the specified criteria"); // TODO i18n
set ("report.waiting.columns", "id,project,priority,wait,age,description"); // TODO i18n
set ("report.waiting.labels", "ID,Project,Pri,Wait,Age,Description"); // TODO i18n
set ("report.waiting.sort", "wait+,priority-,project+"); // TODO i18n
set ("report.waiting.filter", "status:waiting"); // TODO i18n
set ("report.all.description", "Lists all tasks matching the specified criteria"); // TODO i18n
set ("report.all.columns", "id,project,priority,due,active,age,description"); // TODO i18n
set ("report.all.labels", "ID,Project,Pri,Due,Active,Age,Description"); // TODO i18n
set ("report.all.sort", "due+,priority-,project+"); // TODO i18n
set ("report.next.description", "Lists the most urgent tasks"); // TODO i18n
set ("report.next.columns", "id,project,priority,due,active,age,description"); // TODO i18n
set ("report.next.labels", "ID,Project,Pri,Due,Active,Age,Description"); // TODO i18n
set ("report.next.sort", "due+,priority-,project+"); // TODO i18n
set ("report.next.filter", "status:pending"); // TODO i18n
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -265,19 +363,19 @@ const std::string Config::get (
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool Config::get (const std::string& key, bool default_value) bool Config::get (const std::string& key, const bool default_value)
{ {
if ((*this).find (key) != (*this).end ()) if ((*this).find (key) != (*this).end ())
{ {
std::string value = lowerCase ((*this)[key]); std::string value = lowerCase ((*this)[key]);
if (value == "t" || if (value == "t" || // TODO i18n
value == "true" || value == "true" || // TODO i18n
value == "1" || value == "1" || // no i18n
value == "yes" || value == "yes" || // TODO i18n
value == "on" || value == "on" || // TODO i18n
value == "enable" || value == "enable" || // TODO i18n
value == "enabled") value == "enabled") // TODO i18n
return true; return true;
return false; return false;

View file

@ -37,14 +37,19 @@ public:
Config (); Config ();
Config (const std::string&); Config (const std::string&);
Config (const Config&);
Config& operator= (const Config&);
bool load (const std::string&); bool load (const std::string&);
void createDefault (const std::string&); void createDefaultRC (const std::string&, const std::string&);
void createDefaultData (const std::string&);
void setDefaults ();
const std::string get (const char*); const std::string get (const char*);
const std::string get (const char*, const char*); const std::string get (const char*, const char*);
const std::string get (const std::string&); const std::string get (const std::string&);
const std::string get (const std::string&, const std::string&); const std::string get (const std::string&, const std::string&);
bool get (const std::string&, bool); bool get (const std::string&, const bool);
int get (const std::string&, const int); int get (const std::string&, const int);
double get (const std::string&, const double); double get (const std::string&, const double);
void set (const std::string&, const int); void set (const std::string&, const int);

757
src/Context.cpp Normal file
View file

@ -0,0 +1,757 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <fstream>
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include "Context.h"
#include "Timer.h"
#include "text.h"
#include "util.h"
#include "main.h"
#include "i18n.h"
#include "../auto.h"
////////////////////////////////////////////////////////////////////////////////
Context::Context ()
: config ()
, filter ()
, keymap ()
, sequence ()
, subst ()
, task ()
, tdb ()
, stringtable ()
, program ("")
, cmd ()
, inShadow (false)
{
}
////////////////////////////////////////////////////////////////////////////////
Context::~Context ()
{
}
////////////////////////////////////////////////////////////////////////////////
void Context::initialize (int argc, char** argv)
{
// Capture the args.
for (int i = 0; i < argc; ++i)
if (i == 0)
{
program = argv[i];
std::string::size_type cal = program.find ("/cal");
if (program == "cal" ||
(cal != std::string::npos && program.length () == cal + 4))
args.push_back ("calendar");
}
else
args.push_back (argv[i]);
initialize ();
}
////////////////////////////////////////////////////////////////////////////////
void Context::initialize ()
{
Timer t ("Context::initialize");
// Load the configuration file from the home directory. If the file cannot
// be found, offer to create a sample one.
loadCorrectConfigFile ();
loadAliases ();
// When redirecting output to a file, do not use color, curses.
if (!isatty (fileno (stdout)))
{
config.set ("curses", "off");
if (! config.get (std::string ("_forcecolor"), false))
config.set ("color", "off");
}
if (config.get ("color", true))
initializeColorRules ();
// Load appropriate stringtable as soon after the config file as possible, to
// allow all subsequent messages to be localizable.
std::string location = expandPath (config.get ("data.location"));
std::string locale = config.get ("locale");
// If there is a locale variant (en-US.<variant>), then strip it.
std::string::size_type period = locale.find ('.');
if (period != std::string::npos)
locale = locale.substr (0, period);
if (locale != "")
stringtable.load (location + "/strings." + locale);
// TODO Handle "--version, -v" right here?
// init TDB.
tdb.clear ();
std::vector <std::string> all;
split (all, location, ',');
foreach (path, all)
tdb.location (expandPath (*path));
}
////////////////////////////////////////////////////////////////////////////////
int Context::run ()
{
Timer t ("Context::run");
std::string output;
try
{
parse (); // Parse command line.
output = dispatch (); // Dispatch to command handlers.
}
catch (const std::string& error)
{
footnote (error);
}
catch (...)
{
footnote (stringtable.get (100, "Unknown error."));
}
// Dump all debug messages.
if (config.get (std::string ("debug"), false))
foreach (d, debugMessages)
std::cout << colorizeDebug (*d) << std::endl;
// Dump all headers.
foreach (h, headers)
std::cout << colorizeHeader (*h) << std::endl;
// Dump the report output.
std::cout << output;
// Dump all footnotes.
foreach (f, footnotes)
std::cout << colorizeFootnote (*f) << std::endl;
return 0;
}
////////////////////////////////////////////////////////////////////////////////
std::string Context::dispatch ()
{
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 (); }
#ifdef FEATURE_SHELL
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 == "" &&
sequence.size ()) { out = handleModify (); }
// 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); }
// If the command is not recognized, display usage.
else { out = shortUsage (); }
// Only update the shadow file if such an update was not suppressed (shadow),
if (cmd.isWriteCommand () && !inShadow)
shadow ();
return out;
}
////////////////////////////////////////////////////////////////////////////////
void Context::shadow ()
{
// Determine if shadow file is enabled.
std::string shadowFile = expandPath (config.get ("shadow.file"));
if (shadowFile != "")
{
inShadow = true; // Prevents recursion in case shadow command writes.
// TODO Reinstate these checks.
/*
// Check for silly shadow file settings.
if (shadowFile == dataLocation + "/pending.data")
throw std::string ("Configuration variable 'shadow.file' is set to "
"overwrite your pending tasks. Please change it.");
if (shadowFile == dataLocation + "/completed.data")
throw std::string ("Configuration variable 'shadow.file' is set to "
"overwrite your completed tasks. Please change it.");
*/
std::string oldCurses = config.get ("curses");
std::string oldColor = config.get ("color");
config.set ("curses", "off");
config.set ("color", "off");
clear ();
// Run report. Use shadow.command, using default.command as a fallback
// with "list" as a default.
std::string command = config.get ("shadow.command",
config.get ("default.command", "list"));
split (args, command, ' ');
initialize ();
parse ();
std::string result = dispatch ();
std::ofstream out (shadowFile.c_str ());
if (out.good ())
{
out << result;
out.close ();
}
else
throw std::string ("Could not write file '") + shadowFile + "'";
config.set ("curses", oldCurses);
config.set ("color", oldColor);
// Optionally display a notification that the shadow file was updated.
if (config.get (std::string ("shadow.notify"), false))
footnote (std::string ("[Shadow file '") + shadowFile + "' updated]");
inShadow = false;
}
}
////////////////////////////////////////////////////////////////////////////////
// Only allows aliases 10 deep.
std::string Context::canonicalize (const std::string& input) const
{
std::string canonical = input;
// First try to autocomplete the alias.
std::vector <std::string> options;
std::vector <std::string> matches;
foreach (name, aliases)
options.push_back (name->first);
autoComplete (input, options, matches);
if (matches.size () == 1)
{
canonical = matches[0];
// Follow the chain.
int i = 10; // Safety valve.
std::map <std::string, std::string>::const_iterator found;
while ((found = aliases.find (canonical)) != aliases.end () && i-- > 0)
canonical = found->second;
if (i < 1)
return input;
}
return canonical;
}
////////////////////////////////////////////////////////////////////////////////
void Context::loadCorrectConfigFile ()
{
// Set up default locations.
struct passwd* pw = getpwuid (getuid ());
if (!pw)
throw std::string (
stringtable.get (
SHELL_READ_PASSWD,
"Could not read home directory from the passwd file."));
std::string home = pw->pw_dir;
std::string rc = home + "/.taskrc";
std::string data = home + "/.task";
// Is there an override for rc?
foreach (arg, args)
{
if (*arg == "--")
break;
else if (arg->substr (0, 3) == "rc:")
{
rc = arg->substr (3, std::string::npos);
args.erase (arg);
header ("Using alternate .taskrc file " + rc); // TODO i18n
break;
}
}
// Load rc file.
config.clear (); // Dump current values.
config.setDefaults (); // Add in the custom reports.
config.load (rc); // Load new file.
if (config.get ("data.location") != "")
data = config.get ("data.location");
// Is there an override for data?
foreach (arg, args)
{
if (*arg == "--")
break;
else if (arg->substr (0, 17) == "rc.data.location:")
{
data = arg->substr (17, std::string::npos);
header ("Using alternate data.location " + data); // TODO i18n
break;
}
}
// 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?"))
{
config.createDefaultRC (rc, data);
}
// Create data location, if necessary.
config.createDefaultData (data);
// Load rc file.
config.clear (); // Dump current values.
config.setDefaults (); // Add in the custom reports.
config.load (rc); // Load new file.
// Apply overrides of type: "rc.name:value"
std::vector <std::string> filtered;
bool foundTerminator = false;
foreach (arg, args)
{
if (*arg == "--")
{
foundTerminator = true;
filtered.push_back (*arg);
}
else if (!foundTerminator &&
arg->substr (0, 3) == "rc.")
{
std::string name;
std::string value;
Nibbler n (*arg);
if (n.getUntil ('.', name) &&
n.skip ('.') &&
n.getUntil (':', name) &&
n.skip (':') &&
n.getUntilEOS (value))
{
config.set (name, value);
footnote (std::string ("Configuration override ") + // TODO i18n
arg->substr (3, std::string::npos));
}
}
else
filtered.push_back (*arg);
}
args = filtered;
}
////////////////////////////////////////////////////////////////////////////////
void Context::loadAliases ()
{
aliases.clear ();
std::vector <std::string> vars;
config.all (vars);
foreach (var, vars)
{
if (var->substr (0, 6) == "alias.")
{
std::string alias = var->substr (6, std::string::npos);
std::string canonical = config.get (*var);
aliases[alias] = canonical;
debug (std::string ("Alias ") + alias + " -> " + canonical);
}
}
}
////////////////////////////////////////////////////////////////////////////////
void Context::parse ()
{
parse (args, cmd, task, sequence, subst, filter);
}
////////////////////////////////////////////////////////////////////////////////
void Context::parse (
std::vector <std::string>& parseArgs,
Cmd& parseCmd,
Task& parseTask,
Sequence& parseSequence,
Subst& parseSubst,
Filter& parseFilter)
{
Timer t ("Context::parse");
Att attribute;
tagAdditions.clear ();
tagRemovals.clear ();
std::string descCandidate = "";
bool terminated = false;
bool foundSequence = false;
bool foundSomethingAfterSequence = false;
foreach (arg, parseArgs)
{
if (!terminated)
{
// The '--' argument shuts off all parsing - everything is an argument.
if (*arg == "--")
{
debug ("parse terminator '" + *arg + "'");
terminated = true;
}
// Sequence
// Note: "add" doesn't require an ID
else if (parseCmd.command != "add" &&
! foundSomethingAfterSequence &&
parseSequence.valid (*arg))
{
debug ("parse sequence '" + *arg + "'");
parseSequence.parse (*arg);
foundSequence = true;
}
// Tags to include begin with '+'.
else if (arg->length () > 1 &&
(*arg)[0] == '+' &&
noSpaces (*arg))
{
debug ("parse tag addition '" + *arg + "'");
if (foundSequence)
foundSomethingAfterSequence = true;
if (arg->find (',') != std::string::npos)
throw stringtable.get (TAGS_NO_COMMA,
"Tags are not permitted to contain commas.");
tagAdditions.push_back (arg->substr (1, std::string::npos));
parseTask.addTag (arg->substr (1, std::string::npos));
}
// Tags to remove begin with '-'.
else if (arg->length () > 1 &&
(*arg)[0] == '-' &&
noSpaces (*arg))
{
debug ("parse tag removal '" + *arg + "'");
if (foundSequence)
foundSomethingAfterSequence = true;
if (arg->find (',') != std::string::npos)
throw stringtable.get (TAGS_NO_COMMA,
"Tags are not permitted to contain commas.");
tagRemovals.push_back (arg->substr (1, std::string::npos));
}
// Atributes - name[.mod]:[value]
else if (attribute.valid (*arg))
{
debug ("parse attribute '" + *arg + "'");
if (foundSequence)
foundSomethingAfterSequence = true;
attribute.parse (*arg);
// There has to be a better way. And it starts with a fresh coffee.
std::string name = attribute.name ();
std::string mod = attribute.mod ();
std::string value = attribute.value ();
if (attribute.validNameValue (name, mod, value))
{
attribute.name (name);
attribute.mod (mod);
attribute.value (value);
parseTask[attribute.name ()] = attribute;
}
// *arg has the appearance of an attribute (foo:bar), but isn't
// recognized, so downgrade it to part of the description.
else
{
if (foundSequence)
foundSomethingAfterSequence = true;
if (descCandidate.length ())
descCandidate += " ";
descCandidate += *arg;
}
}
// Substitution of description and/or annotation text.
else if (parseSubst.valid (*arg))
{
if (foundSequence)
foundSomethingAfterSequence = true;
debug ("parse subst '" + *arg + "'");
parseSubst.parse (*arg);
}
// It might be a command if one has not already been found.
else if (parseCmd.command == "" &&
parseCmd.valid (*arg))
{
debug ("parse cmd '" + *arg + "'");
parseCmd.parse (*arg);
if (foundSequence)
foundSomethingAfterSequence = true;
}
// Anything else is just considered description.
else
{
if (foundSequence)
foundSomethingAfterSequence = true;
if (descCandidate.length ())
descCandidate += " ";
descCandidate += *arg;
}
}
// Command is terminated, therefore everything subsequently is a description.
else
{
debug ("parse post-termination description '" + *arg + "'");
if (foundSequence)
foundSomethingAfterSequence = true;
if (descCandidate.length ())
descCandidate += " ";
descCandidate += *arg;
}
}
if (descCandidate != "" && noVerticalSpace (descCandidate))
{
debug ("parse description '" + descCandidate + "'");
parseTask.set ("description", descCandidate);
}
// At this point, either a sequence or a command should have been found.
if (parseSequence.size () == 0 && parseCmd.command == "")
parseCmd.parse (descCandidate);
// Read-only command (reports, status, info ...) use filters. Write commands
// (add, done ...) do not.
if (parseCmd.isReadOnlyCommand ())
autoFilter (parseTask, parseFilter);
// If no command was specified, and there were no command line arguments
// then invoke the default command.
if (parseCmd.command == "" && parseArgs.size () == 0)
{
std::string defaultCommand = config.get ("default.command");
if (defaultCommand != "")
{
// Stuff the command line.
parseArgs.clear ();
split (parseArgs, defaultCommand, ' ');
header ("[task " + defaultCommand + "]");
// Reinitialize the context and recurse.
initialize ();
parse (args, cmd, task, sequence, subst, filter);
}
else
throw stringtable.get (
CMD_MISSING,
"You must specify a command, or a task ID to modify");
}
}
////////////////////////////////////////////////////////////////////////////////
void Context::clear ()
{
// Config config;
filter.clear ();
// Keymap keymap;
sequence.clear ();
subst.clear ();
// task.clear ();
task = Task ();
tdb.clear ();
// stringtable.clear ();
program = "";
args.clear ();
cmd.command = "";
tagAdditions.clear ();
tagRemovals.clear ();
clearMessages ();
inShadow = false;
}
////////////////////////////////////////////////////////////////////////////////
// Add all the attributes in the task to the filter. All except uuid.
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 () == "")
{
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);
}
}
// Projects are matched left-most.
else if (att->first == "project" && att->second.mod () == "")
{
if (att->second.value () != "")
{
f.push_back (Att ("project", "startswith", att->second.value ()));
debug ("auto filter: " + att->first + ".startswith:" + att->second.value ());
}
else
{
f.push_back (Att ("project", "is", att->second.value ()));
debug ("auto filter: " + att->first + ".is:" + att->second.value ());
}
}
// The limit attribute does not participate in filtering, and needs to be
// specifically handled in handleCustomReport.
else if (att->first == "limit")
{
}
// Every task has a unique uuid by default, and it shouldn't be included,
// because it is guaranteed to not match.
else if (att->first == "uuid")
{
}
// The mechanism for filtering on tags is +/-<tag>.
else if (att->first == "tags")
{
}
// Generic attribute matching.
else
{
f.push_back (att->second);
debug ("auto filter: " +
att->first +
(att->second.mod () != "" ?
("." + att->second.mod () + ":") :
":") +
att->second.value ());
}
}
// Include tagAdditions.
foreach (tag, tagAdditions)
{
f.push_back (Att ("tags", "has", *tag));
debug ("auto filter: +" + *tag);
}
// Include tagRemovals.
foreach (tag, tagRemovals)
{
f.push_back (Att ("tags", "hasnt", *tag));
debug ("auto filter: -" + *tag);
}
}
////////////////////////////////////////////////////////////////////////////////
void Context::header (const std::string& input)
{
headers.push_back (input);
}
////////////////////////////////////////////////////////////////////////////////
void Context::footnote (const std::string& input)
{
footnotes.push_back (input);
}
////////////////////////////////////////////////////////////////////////////////
void Context::debug (const std::string& input)
{
debugMessages.push_back (input);
}
////////////////////////////////////////////////////////////////////////////////
void Context::clearMessages ()
{
headers.clear ();
footnotes.clear ();
debugMessages.clear ();
}
////////////////////////////////////////////////////////////////////////////////

98
src/Context.h Normal file
View file

@ -0,0 +1,98 @@
////////////////////////////////////////////////////////////////////////////////
// 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_CONTEXT
#define INCLUDED_CONTEXT
#include "Filter.h"
#include "Keymap.h"
#include "Config.h"
#include "Sequence.h"
#include "Subst.h"
#include "Cmd.h"
#include "Task.h"
#include "TDB.h"
#include "StringTable.h"
class Context
{
public:
Context (); // Default constructor
~Context (); // Destructor
Context (const Context&);
Context& operator= (const Context&);
void initialize (int, char**); // all startup
void initialize (); // for reinitializing
int run (); // task classic
int interactive (); // task interactive (not implemented)
std::string dispatch (); // command handler dispatch
void shadow (); // shadow file update
int getWidth (); // determine terminal width
void header (const std::string&); // Header message sink
void footnote (const std::string&); // Footnote message sink
void debug (const std::string&); // Debug message sink
void clearMessages ();
void parse ();
void parse (std::vector <std::string>&, Cmd&, Task&, Sequence&, Subst&, Filter&);
void clear ();
std::string canonicalize (const std::string&) const;
private:
void loadCorrectConfigFile ();
void loadAliases ();
void autoFilter (Task&, Filter&);
public:
Config config;
Filter filter;
Keymap keymap;
Sequence sequence;
Subst subst;
Task task;
TDB tdb;
StringTable stringtable;
std::string program;
std::vector <std::string> args;
Cmd cmd;
std::map <std::string, std::string> aliases;
std::vector <std::string> tagAdditions;
std::vector <std::string> tagRemovals;
private:
std::vector <std::string> headers;
std::vector <std::string> footnotes;
std::vector <std::string> debugMessages;
bool inShadow;
};
#endif
////////////////////////////////////////////////////////////////////////////////

View file

@ -25,11 +25,13 @@
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <iostream> #include <iostream>
#include <sstream>
#include <time.h> #include <time.h>
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include "task.h"
#include "Date.h" #include "Date.h"
#include "text.h"
#include "util.h"
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Defaults to "now". // Defaults to "now".
@ -63,6 +65,10 @@ Date::Date (const std::string& mdy, const std::string& format /* = "m/d/Y" */)
int day = 0; int day = 0;
int year = 0; int year = 0;
// Perhaps it is an epoch date, in string form?
if (isEpoch (mdy))
return;
// Before parsing according to "format", perhaps this is a relative date? // Before parsing according to "format", perhaps this is a relative date?
if (isRelativeDate (mdy)) if (isRelativeDate (mdy))
return; return;
@ -179,6 +185,9 @@ Date::Date (const std::string& mdy, const std::string& format /* = "m/d/Y" */)
} }
} }
if (i < mdy.length ())
throw std::string ("\"") + mdy + "\" is not a valid date in " + format + " format.";
if (!valid (month, day, year)) if (!valid (month, day, year))
throw std::string ("\"") + mdy + "\" is not a valid date."; throw std::string ("\"") + mdy + "\" is not a valid date.";
@ -208,6 +217,14 @@ time_t Date::toEpoch ()
return mT; return mT;
} }
////////////////////////////////////////////////////////////////////////////////
std::string Date::toEpochString ()
{
std::stringstream epoch;
epoch << mT;
return epoch.str ();
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void Date::toEpoch (time_t& epoch) void Date::toEpoch (time_t& epoch)
{ {
@ -253,6 +270,22 @@ const std::string Date::toString (const std::string& format /*= "m/d/Y" */) cons
return formatted; return formatted;
} }
////////////////////////////////////////////////////////////////////////////////
bool Date::valid (const std::string& input, const std::string& format)
{
try
{
Date test (input, format);
}
catch (...)
{
return false;
}
return true;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool Date::valid (const int m, const int d, const int y) bool Date::valid (const int m, const int d, const int y)
{ {
@ -277,9 +310,11 @@ bool Date::leapYear (int year)
{ {
bool ly = false; bool ly = false;
if (!(year % 4)) ly = true; // (year % 4 == 0) && (year % 100 !=0) OR
else if (!(year % 400)) ly = true; // (year % 400 == 0)
else if (!(year % 100)) ly = false; // are leapyears
if (((!(year % 4)) && (year % 100)) || (!(year % 400))) ly = true;
return ly; return ly;
} }
@ -354,6 +389,28 @@ std::string Date::dayName (int dow)
return days[dow]; return days[dow];
} }
////////////////////////////////////////////////////////////////////////////////
int Date::weekOfYear (int weekStart) const
{
struct tm* t = localtime (&mT);
char weekStr[3];
if (weekStart == 0)
strftime(weekStr, sizeof(weekStr), "%U", t);
else if (weekStart == 1)
strftime(weekStr, sizeof(weekStr), "%V", t);
else
throw std::string ("The 'weekstart' configuration variable may "
"only contain 'Sunday' or 'Monday'.");
int weekNumber = ::atoi (weekStr);
if (weekStart == 0)
weekNumber += 1;
return weekNumber;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int Date::dayOfWeek () const int Date::dayOfWeek () const
{ {
@ -490,6 +547,19 @@ time_t Date::operator- (const Date& rhs)
return mT - rhs.mT; return mT - rhs.mT;
} }
////////////////////////////////////////////////////////////////////////////////
bool Date::isEpoch (const std::string& input)
{
if (digitsOnly (input) &&
input.length () > 8)
{
mT = (time_t) ::atoi (input.c_str ());
return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// If the input string looks like a relative date, determine that date, set mT // If the input string looks like a relative date, determine that date, set mT
// and return true. // and return true.

View file

@ -44,8 +44,10 @@ public:
void toEpoch (time_t&); void toEpoch (time_t&);
time_t toEpoch (); time_t toEpoch ();
std::string toEpochString ();
void toMDY (int&, int&, int&); void toMDY (int&, int&, int&);
const std::string toString (const std::string& format = "m/d/Y") const; const std::string toString (const std::string& format = "m/d/Y") const;
static bool valid (const std::string&, const std::string& format = "m/d/Y");
static bool valid (const int, const int, const int); static bool valid (const int, const int, const int);
static bool leapYear (int); static bool leapYear (int);
@ -53,11 +55,13 @@ public:
static std::string monthName (int); static std::string monthName (int);
static void dayName (int, std::string&); static void dayName (int, std::string&);
static std::string dayName (int); static std::string dayName (int);
static int weekOfYear (const std::string&);
static int dayOfWeek (const std::string&); static int dayOfWeek (const std::string&);
int month () const; int month () const;
int day () const; int day () const;
int year () const; int year () const;
int weekOfYear (int) const;
int dayOfWeek () const; int dayOfWeek () const;
bool operator== (const Date&); bool operator== (const Date&);
@ -77,6 +81,7 @@ public:
time_t operator- (const Date&); time_t operator- (const Date&);
private: private:
bool isEpoch (const std::string&);
bool isRelativeDate (const std::string&); bool isRelativeDate (const std::string&);
protected: protected:

205
src/Duration.cpp Normal file
View file

@ -0,0 +1,205 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#include <sstream>
#include <string>
#include <vector>
#include <stdlib.h>
#include "text.h"
#include "util.h"
#include "Duration.h"
////////////////////////////////////////////////////////////////////////////////
Duration::Duration ()
: mDays (0)
{
}
////////////////////////////////////////////////////////////////////////////////
Duration::Duration (time_t input)
{
mDays = input;
}
////////////////////////////////////////////////////////////////////////////////
Duration::Duration (const std::string& input)
{
parse (input);
}
////////////////////////////////////////////////////////////////////////////////
Duration::operator int ()
{
return (int) mDays;
}
////////////////////////////////////////////////////////////////////////////////
Duration::operator time_t ()
{
return mDays;
}
////////////////////////////////////////////////////////////////////////////////
Duration::operator std::string ()
{
std::stringstream s;
s << mDays;
return s.str ();
}
////////////////////////////////////////////////////////////////////////////////
bool Duration::operator< (const Duration& other)
{
return mDays < other.mDays;
}
////////////////////////////////////////////////////////////////////////////////
bool Duration::operator> (const Duration& other)
{
return mDays > other.mDays;
}
////////////////////////////////////////////////////////////////////////////////
Duration::~Duration ()
{
}
////////////////////////////////////////////////////////////////////////////////
bool Duration::valid (const std::string& input) const
{
std::string lower_input = lowerCase (input);
std::vector <std::string> supported;
supported.push_back ("daily"); // TODO i18n
supported.push_back ("day"); // TODO i18n
supported.push_back ("weekly"); // TODO i18n
supported.push_back ("weekdays"); // TODO i18n
supported.push_back ("sennight"); // TODO i18n
supported.push_back ("biweekly"); // TODO i18n
supported.push_back ("fortnight"); // TODO i18n
supported.push_back ("monthly"); // TODO i18n
supported.push_back ("bimonthly"); // TODO i18n
supported.push_back ("quarterly"); // TODO i18n
supported.push_back ("biannual"); // TODO i18n
supported.push_back ("biyearly"); // TODO i18n
supported.push_back ("annual"); // TODO i18n
supported.push_back ("semiannual"); // TODO i18n
supported.push_back ("yearly"); // TODO i18n
std::vector <std::string> matches;
if (autoComplete (lower_input, supported, matches) == 1)
return true;
// Support \d+ d|w|m|q|y
// Verify all digits followed by d, w, m, q, or y.
unsigned int length = lower_input.length ();
for (unsigned int i = 0; i < length; ++i)
{
if (! isdigit (lower_input[i]) &&
i == length - 1)
{
std::string type = lower_input.substr (length - 1, std::string::npos);
if (type == "d" || // TODO i18n
type == "w" || // TODO i18n
type == "m" || // TODO i18n
type == "q" || // TODO i18n
type == "y") // TODO i18n
return true;
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
void Duration::parse (const std::string& input)
{
std::string lower_input = lowerCase (input);
std::vector <std::string> supported;
supported.push_back ("daily"); // TODO i18n
supported.push_back ("day"); // TODO i18n
supported.push_back ("weekly"); // TODO i18n
supported.push_back ("weekdays"); // TODO i18n
supported.push_back ("sennight"); // TODO i18n
supported.push_back ("biweekly"); // TODO i18n
supported.push_back ("fortnight"); // TODO i18n
supported.push_back ("monthly"); // TODO i18n
supported.push_back ("bimonthly"); // TODO i18n
supported.push_back ("quarterly"); // TODO i18n
supported.push_back ("biannual"); // TODO i18n
supported.push_back ("biyearly"); // TODO i18n
supported.push_back ("annual"); // TODO i18n
supported.push_back ("semiannual"); // TODO i18n
supported.push_back ("yearly"); // TODO i18n
std::vector <std::string> matches;
if (autoComplete (lower_input, supported, matches) == 1)
{
std::string found = matches[0];
if (found == "daily" || found == "day") mDays = 1; // TODO i18n
else if (found == "weekdays") mDays = 1; // TODO i18n
else if (found == "weekly" || found == "sennight") mDays = 7; // TODO i18n
else if (found == "biweekly" || found == "fortnight") mDays = 14; // TODO i18n
else if (found == "monthly") mDays = 30; // TODO i18n
else if (found == "bimonthly") mDays = 61; // TODO i18n
else if (found == "quarterly") mDays = 91; // TODO i18n
else if (found == "semiannual") mDays = 183; // TODO i18n
else if (found == "yearly" || found == "annual") mDays = 365; // TODO i18n
else if (found == "biannual" || found == "biyearly") mDays = 730; // TODO i18n
}
// Support \d+ d|w|m|q|y
else
{
// Verify all digits followed by d, w, m, q, or y.
unsigned int length = lower_input.length ();
for (unsigned int i = 0; i < length; ++i)
{
if (! isdigit (lower_input[i]) &&
i == length - 1)
{
int number = ::atoi (lower_input.substr (0, i).c_str ());
switch (lower_input[length - 1])
{
case 'd': mDays = number * 1; break; // TODO i18n
case 'w': mDays = number * 7; break; // TODO i18n
case 'm': mDays = number * 30; break; // TODO i18n
case 'q': mDays = number * 91; break; // TODO i18n
case 'y': mDays = number * 365; break; // TODO i18n
}
}
}
}
if (mDays == 0)
throw std::string ("The duration '") + input + "' was not recognized."; // TODO i18n
}
////////////////////////////////////////////////////////////////////////////////

55
src/Duration.h Normal file
View file

@ -0,0 +1,55 @@
////////////////////////////////////////////////////////////////////////////////
// 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_DURATION
#define INCLUDED_DURATION
#include <string>
#include <time.h>
class Duration
{
public:
Duration (); // Default constructor
Duration (time_t); // Default constructor
Duration (const std::string&); // Parse
bool operator< (const Duration&);
bool operator> (const Duration&);
~Duration (); // Destructor
operator int ();
operator time_t ();
operator std::string ();
bool valid (const std::string&) const;
void parse (const std::string&);
private:
time_t mDays;
};
#endif
////////////////////////////////////////////////////////////////////////////////

134
src/Filter.cpp Normal file
View file

@ -0,0 +1,134 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#include <sstream>
#include "Filter.h"
#include "util.h"
#include "main.h"
////////////////////////////////////////////////////////////////////////////////
// For every Att in the filter, lookup the equivalent in Record, and perform a
// match. Aren't filters easy now that everything is an attribute?
bool Filter::pass (const Record& record) const
{
Record::const_iterator r;
// First do description/annotation matches.
foreach (att, (*this))
{
// Descriptions have special handling.
if (att->name () == "description")
{
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;
}
}
}
if (!annoMatch)
return false;
}
}
else if (! att->match (Att ()))
return false;
}
// Annotations are skipped.
else if (att->name ().length () > 11 &&
att->name ().substr (0, 11) == "annotation_")
{
}
else
{
// An individual attribute match failure is enough to fail the filter.
if ((r = record.find (att->name ())) != record.end ())
{
if (! att->match (r->second))
return false;
}
else if (! att->match (Att ()))
return false;
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
void Filter::applySequence (std::vector<Task>& all, Sequence& sequence)
{
std::vector <Task> filtered;
foreach (task, all)
foreach (i, sequence)
if (task->id == *i)
filtered.push_back (*task);
if (sequence.size () != filtered.size ())
{
std::vector <int> filteredSequence;
foreach (task, filtered)
filteredSequence.push_back (task->id);
std::vector <int> left;
std::vector <int> right;
listDiff (filteredSequence, (std::vector <int>&)sequence, left, right);
if (left.size ())
throw std::string ("Sequence filtering error - please report this error");
if (right.size ())
{
std::stringstream out;
out << "Task";
if (right.size () > 1) out << "s";
foreach (r, right)
out << " " << *r;
out << " not found";
throw out.str ();
}
}
all = filtered;
}
////////////////////////////////////////////////////////////////////////////////

43
src/Filter.h Normal file
View file

@ -0,0 +1,43 @@
////////////////////////////////////////////////////////////////////////////////
// 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_FILTER
#define INCLUDED_FILTER
#include <vector>
#include "Att.h"
#include "Task.h"
#include "Record.h"
class Filter : public std::vector <Att>
{
public:
bool pass (const Record&) const;
void applySequence (std::vector<Task>&, Sequence&);
};
#endif
////////////////////////////////////////////////////////////////////////////////

View file

@ -306,7 +306,7 @@ Grid::Cell::operator char () const
{ {
switch (mType) switch (mType)
{ {
case CELL_BOOL: return mBool ? 'Y' : 'N'; case CELL_BOOL: return mBool ? 'Y' : 'N'; // TODO i18n
case CELL_CHAR: return mChar; case CELL_CHAR: return mChar;
case CELL_INT: return (char) mInt; case CELL_INT: return (char) mInt;
case CELL_FLOAT: return (char) (int) mFloat; case CELL_FLOAT: return (char) (int) mFloat;
@ -368,7 +368,7 @@ Grid::Cell::operator std::string () const
switch (mType) switch (mType)
{ {
case CELL_BOOL: return mBool ? "true" : "false"; case CELL_BOOL: return mBool ? "true" : "false"; // TODO i18n
case CELL_CHAR: sprintf (s, "%c", mChar); case CELL_CHAR: sprintf (s, "%c", mChar);
return std::string (s); return std::string (s);
case CELL_INT: sprintf (s, "%d", mInt); case CELL_INT: sprintf (s, "%d", mInt);

View file

@ -45,6 +45,9 @@ public:
Cell (const double); Cell (const double);
Cell (const std::string&); Cell (const std::string&);
Cell (const Cell&);
Cell& operator= (const Cell&);
operator bool () const; operator bool () const;
operator char () const; operator char () const;
operator int () const; operator int () const;
@ -72,6 +75,9 @@ public:
Grid (); Grid ();
~Grid (); ~Grid ();
Grid (const Grid&);
Grid& operator= (const Grid&);
void add (const unsigned int, const unsigned int, const bool); void add (const unsigned int, const unsigned int, const bool);
void add (const unsigned int, const unsigned int, const char); void add (const unsigned int, const unsigned int, const char);
void add (const unsigned int, const unsigned int, const int); void add (const unsigned int, const unsigned int, const int);

66
src/Keymap.cpp Normal file
View file

@ -0,0 +1,66 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#include <string>
#include "Keymap.h"
////////////////////////////////////////////////////////////////////////////////
Keymap::Keymap ()
{
}
////////////////////////////////////////////////////////////////////////////////
Keymap::Keymap (const Keymap& other)
{
throw std::string ("unimplemented Keymap::Keymap");
// mOne = other.mOne;
}
////////////////////////////////////////////////////////////////////////////////
Keymap& Keymap::operator= (const Keymap& other)
{
throw std::string ("unimplemented Keymap::operator=");
if (this != &other)
{
// mOne = other.mOne;
}
return *this;
}
////////////////////////////////////////////////////////////////////////////////
Keymap::~Keymap ()
{
}
////////////////////////////////////////////////////////////////////////////////
void Keymap::load (const std::string& file)
{
throw std::string ("unimplemented Keymap::load");
}
////////////////////////////////////////////////////////////////////////////////

51
src/Keymap.h Normal file
View file

@ -0,0 +1,51 @@
////////////////////////////////////////////////////////////////////////////////
// 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_KEYMAP
#define INCLUDED_KEYMAP
#include <string>
class Keymap
{
public:
Keymap (); // Default constructor
Keymap (const Keymap&); // Copy constructor
Keymap& operator= (const Keymap&); // Assignment operator
~Keymap (); // Destructor
void load (const std::string&); // Load the map file
/*
real (); // Convert soft to real
soft (); // Convert real to soft
*/
private:
// TODO Structure for mapping strings to keys.
};
#endif
////////////////////////////////////////////////////////////////////////////////

73
src/Location.cpp Normal file
View file

@ -0,0 +1,73 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#include "Location.h"
////////////////////////////////////////////////////////////////////////////////
Location::Location ()
: path ("")
, pending (NULL)
, completed (NULL)
, undo (NULL)
{
}
////////////////////////////////////////////////////////////////////////////////
Location::Location (const std::string& p)
: path (p)
{
}
////////////////////////////////////////////////////////////////////////////////
Location::Location (const Location& other)
{
path = other.path;
pending = other.pending;
completed = other.completed;
undo = other.undo;
}
////////////////////////////////////////////////////////////////////////////////
Location& Location::operator= (const Location& other)
{
if (this != &other)
{
path = other.path;
pending = other.pending;
completed = other.completed;
undo = other.undo;
}
return *this;
}
////////////////////////////////////////////////////////////////////////////////
Location::~Location ()
{
}
////////////////////////////////////////////////////////////////////////////////

50
src/Location.h Normal file
View file

@ -0,0 +1,50 @@
////////////////////////////////////////////////////////////////////////////////
// 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_LOCATION
#define INCLUDED_LOCATION
#include <string>
#include <stdio.h>
class Location
{
public:
Location (); // Default constructor
Location (const std::string&); // Default constructor
Location (const Location&); // Copy constructor
Location& operator= (const Location&); // Assignment operator
~Location (); // Destructor
public:
std::string path;
FILE* pending;
FILE* completed;
FILE* undo;
};
#endif
////////////////////////////////////////////////////////////////////////////////

View file

@ -1,2 +1,11 @@
bin_PROGRAMS = task bin_PROGRAMS = task
task_SOURCES = Config.cpp Date.cpp T.cpp TDB.cpp Table.cpp Grid.cpp Timer.cpp color.cpp parse.cpp task.cpp command.cpp edit.cpp report.cpp util.cpp text.cpp rules.cpp import.cpp Config.h Date.h T.h TDB.h Table.h Grid.h Timer.h color.h task.h task_SOURCES = Att.cpp Cmd.cpp Config.cpp Context.cpp Date.cpp Duration.cpp \
Filter.cpp Grid.cpp Keymap.cpp Location.cpp Nibbler.cpp \
Record.cpp Sequence.cpp StringTable.cpp Subst.cpp Task.cpp \
TDB.cpp Table.cpp Timer.cpp Permission.cpp color.cpp edit.cpp \
command.cpp import.cpp interactive.cpp recur.cpp report.cpp \
custom.cpp rules.cpp main.cpp text.cpp util.cpp \
Att.h Cmd.h Config.h Context.h Date.h Duration.h Filter.h \
Grid.h Keymap.h Location.h Nibbler.h Record.h Sequence.h \
StringTable.h Subst.h Task.h TDB.h Table.h Timer.h \
Permission.h color.h i18n.h main.h text.h util.h

304
src/Nibbler.cpp Normal file
View file

@ -0,0 +1,304 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <ctype.h>
#include "Nibbler.h"
////////////////////////////////////////////////////////////////////////////////
Nibbler::Nibbler ()
: mInput ("")
, mCursor (0)
{
}
////////////////////////////////////////////////////////////////////////////////
Nibbler::Nibbler (const char* input)
: mInput (input)
, mCursor (0)
{
}
////////////////////////////////////////////////////////////////////////////////
Nibbler::Nibbler (const std::string& input)
: mInput (input)
, mCursor (0)
{
}
////////////////////////////////////////////////////////////////////////////////
Nibbler::Nibbler (const Nibbler& other)
{
mInput = other.mInput;
mCursor = other.mCursor;
}
////////////////////////////////////////////////////////////////////////////////
Nibbler& Nibbler::operator= (const Nibbler& other)
{
if (this != &other)
{
mInput = other.mInput;
mCursor = other.mCursor;
}
return *this;
}
////////////////////////////////////////////////////////////////////////////////
Nibbler::~Nibbler ()
{
}
////////////////////////////////////////////////////////////////////////////////
// Extract up until the next c, or EOS.
bool Nibbler::getUntil (char c, std::string& result)
{
if (mCursor < mInput.length ())
{
std::string::size_type i = mInput.find (c, mCursor);
if (i != std::string::npos)
{
result = mInput.substr (mCursor, i - mCursor);
mCursor = i;
}
else
{
result = mInput.substr (mCursor, std::string::npos);
mCursor = mInput.length ();
}
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool Nibbler::getUntil (const std::string& terminator, std::string& result)
{
if (mCursor < mInput.length ())
{
std::string::size_type i = mInput.find (terminator, mCursor);
if (i != std::string::npos)
{
result = mInput.substr (mCursor, i - mCursor);
mCursor = i;
}
else
{
result = mInput.substr (mCursor, std::string::npos);
mCursor = mInput.length ();
}
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool Nibbler::getUntilOneOf (const std::string& chars, std::string& result)
{
if (mCursor < mInput.length ())
{
std::string::size_type i = mInput.find_first_of (chars, mCursor);
if (i != std::string::npos)
{
result = mInput.substr (mCursor, i - mCursor);
mCursor = i;
}
else
{
result = mInput.substr (mCursor, std::string::npos);
mCursor = mInput.length ();
}
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool Nibbler::skipN (const int quantity /* = 1 */)
{
if (mCursor >= mInput.length ())
return false;
if (mCursor <= mInput.length () - quantity)
{
mCursor += quantity;
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool Nibbler::skip (char c)
{
if (mCursor < mInput.length () &&
mInput[mCursor] == c)
{
++mCursor;
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool Nibbler::skipAll (char c)
{
std::string::size_type i = mCursor;
while (i < mInput.length () && mInput[i] == c)
++i;
if (i != mCursor)
{
mCursor = i;
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool Nibbler::skipAllOneOf (const std::string& chars)
{
if (mCursor < mInput.length ())
{
std::string::size_type i = mInput.find_first_not_of (chars, mCursor);
if (i == mCursor)
return false;
if (i == std::string::npos)
mCursor = mInput.length (); // Yes, off the end.
else
mCursor = i;
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool Nibbler::getQuoted (char c, std::string& result)
{
std::string::size_type start = mCursor;
if (start < mInput.length () && mInput[start] == c)
{
++start;
if (start < mInput.length ())
{
std::string::size_type end = mInput.find (c, start);
if (end != std::string::npos)
{
result = mInput.substr (start, end - start);
mCursor = end + 1;
return true;
}
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool Nibbler::getInt (int& result)
{
std::string::size_type i = mCursor;
if (i < mInput.length ())
{
if (mInput[i] == '-')
++i;
else if (mInput[i] == '+')
++i;
}
while (i < mInput.length () && ::isdigit (mInput[i]))
++i;
if (i > mCursor)
{
result = ::atoi (mInput.substr (mCursor, i - mCursor).c_str ());
mCursor = i;
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool Nibbler::getUnsignedInt (int& result)
{
std::string::size_type i = mCursor;
while (i < mInput.length () && ::isdigit (mInput[i]))
++i;
if (i > mCursor)
{
result = ::atoi (mInput.substr (mCursor, i - mCursor).c_str ());
mCursor = i;
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool Nibbler::getUntilEOL (std::string& result)
{
return getUntil ('\n', result);
}
////////////////////////////////////////////////////////////////////////////////
bool Nibbler::getUntilEOS (std::string& result)
{
if (mCursor < mInput.length ())
{
result = mInput.substr (mCursor, std::string::npos);
mCursor = mInput.length ();
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool Nibbler::depleted ()
{
if (mCursor >= mInput.length ())
return true;
return false;
}
////////////////////////////////////////////////////////////////////////////////

62
src/Nibbler.h Normal file
View file

@ -0,0 +1,62 @@
////////////////////////////////////////////////////////////////////////////////
// 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_NIBBLER
#define INCLUDED_NIBBLER
#include <string>
class Nibbler
{
public:
Nibbler (); // Default constructor
Nibbler (const char*); // Constructor
Nibbler (const std::string&); // Constructor
Nibbler (const Nibbler&); // Copy constructor
Nibbler& operator= (const Nibbler&); // Assignment operator
~Nibbler (); // Destructor
bool getUntil (char, std::string&);
bool getUntil (const std::string&, std::string&);
bool getUntilOneOf (const std::string&, std::string&);
bool skipN (const int quantity = 1);
bool skip (char);
bool skipAll (char);
bool skipAllOneOf (const std::string&);
bool getQuoted (char, std::string&);
bool getInt (int&);
bool getUnsignedInt (int&i);
bool getUntilEOL (std::string&);
bool getUntilEOS (std::string&);
bool depleted ();
private:
std::string mInput;
std::string::size_type mCursor;
};
#endif
////////////////////////////////////////////////////////////////////////////////

74
src/Permission.cpp Normal file
View file

@ -0,0 +1,74 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include "Permission.h"
#include "Context.h"
#include "util.h"
#include "i18n.h"
extern Context context;
////////////////////////////////////////////////////////////////////////////////
Permission::Permission ()
: needConfirmation (false)
, allConfirmed (false)
{
// Turning confirmations off is the same as entering "all".
if (context.config.get ("confirmation", true) == false)
allConfirmed = true;
}
////////////////////////////////////////////////////////////////////////////////
bool Permission::confirmed (const Task& task, const std::string& question)
{
if (!needConfirmation)
return true;
if (allConfirmed)
return true;
std::cout << std::endl
<< "Task "
<< task.id
<< " \""
<< task.get ("description")
<< "\""
<< std::endl;
int answer = confirm3 (question);
if (answer == 2)
allConfirmed = true;
if (answer > 0)
return true;
return false;
}
////////////////////////////////////////////////////////////////////////////////

50
src/Permission.h Normal file
View file

@ -0,0 +1,50 @@
////////////////////////////////////////////////////////////////////////////////
// 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_PERMISSION
#define INCLUDED_PERMISSION
#include <string>
#include "Task.h"
class Permission
{
public:
Permission ();
Permission (const Permission&);
Permission& operator= (const Permission&);
void bigChange () { needConfirmation = true; }
void bigSequence () { needConfirmation = true; }
bool confirmed (const Task&, const std::string&);
private:
bool needConfirmation;
bool allConfirmed;
};
#endif
////////////////////////////////////////////////////////////////////////////////

183
src/Record.cpp Normal file
View file

@ -0,0 +1,183 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <sstream>
#include <stdlib.h>
#include "util.h"
#include "Nibbler.h"
#include "Context.h"
#include "i18n.h"
#include "Record.h"
extern Context context;
////////////////////////////////////////////////////////////////////////////////
Record::Record ()
{
}
////////////////////////////////////////////////////////////////////////////////
Record::Record (const std::string& input)
{
parse (input);
}
////////////////////////////////////////////////////////////////////////////////
Record::~Record ()
{
}
////////////////////////////////////////////////////////////////////////////////
// The format is:
//
// [ Att::composeF4 ... ] \n
//
std::string Record::composeF4 () const
{
std::string ff4 = "[";
bool first = true;
std::map <std::string, Att>::const_iterator it;
for (it = this->begin (); it != this->end (); ++it)
{
if (it->second.value () != "")
{
ff4 += (first ? "" : " ") + it->second.composeF4 ();
first = false;
}
}
ff4 += "]\n";
return ff4;
}
////////////////////////////////////////////////////////////////////////////////
//
// start --> [ --> Att --> ] --> end
// ^ |
// +-------+
//
void Record::parse (const std::string& input)
{
clear ();
Nibbler n (input);
std::string line;
if (n.skip ('[') &&
n.getUntil (']', line) &&
n.skip (']') &&
n.depleted ())
{
if (line.length () == 0)
throw context.stringtable.get (RECORD_EMPTY,
"Empty record in input");
Nibbler nl (line);
Att a;
while (!nl.depleted ())
{
a.parse (nl);
(*this)[a.name ()] = a;
nl.skip (' ');
}
std::string remainder;
nl.getUntilEOS (remainder);
if (remainder.length ())
throw context.stringtable.get (RECORD_EXTRA,
"Unrecognized characters at end of line");
}
else
throw context.stringtable.get (RECORD_NOT_FF4,
"Record not recognized as format 4");
}
////////////////////////////////////////////////////////////////////////////////
bool Record::has (const std::string& name) const
{
Record::const_iterator i = this->find (name);
if (i != this->end ())
return true;
return false;
}
////////////////////////////////////////////////////////////////////////////////
std::vector <Att> Record::all ()
{
std::vector <Att> all;
foreach (a, (*this))
all.push_back (a->second);
return all;
}
////////////////////////////////////////////////////////////////////////////////
const std::string Record::get (const std::string& name) const
{
Record::const_iterator i = this->find (name);
if (i != this->end ())
return i->second.value ();
return "";
}
////////////////////////////////////////////////////////////////////////////////
int Record::get_int (const std::string& name) const
{
Record::const_iterator i = this->find (name);
if (i != this->end ())
return ::atoi (i->second.value ().c_str ());
return 0;
}
////////////////////////////////////////////////////////////////////////////////
void Record::set (const std::string& name, const std::string& value)
{
(*this)[name] = Att (name, value);
}
////////////////////////////////////////////////////////////////////////////////
void Record::set (const std::string& name, int value)
{
std::stringstream svalue;
svalue << value;
(*this)[name] = Att (name, svalue.str ());
}
////////////////////////////////////////////////////////////////////////////////
void Record::remove (const std::string& name)
{
Record::iterator it;
if ((it = this->find (name)) != this->end ())
this->erase (it);
}
////////////////////////////////////////////////////////////////////////////////

56
src/Record.h Normal file
View file

@ -0,0 +1,56 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_RECORD
#define INCLUDED_RECORD
#include <vector>
#include <map>
#include <string>
#include "Att.h"
class Record : public std::map <std::string, Att>
{
public:
Record (); // Default constructor
Record (const std::string&); // Copy constructor
virtual ~Record (); // Destructor
std::string composeF4 () const;
std::string composeCSV () const;
void parse (const std::string&);
bool has (const std::string&) const;
std::vector <Att> all ();
const std::string get (const std::string&) const;
int get_int (const std::string&) const;
void set (const std::string&, const std::string&);
void set (const std::string&, int);
void remove (const std::string&);
};
#endif
////////////////////////////////////////////////////////////////////////////////

162
src/Sequence.cpp Normal file
View file

@ -0,0 +1,162 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#include <map>
#include <string>
#include <algorithm>
#include <ctype.h>
#include "util.h"
#include "text.h"
#include "i18n.h"
#include "Context.h"
#include "Sequence.h"
extern Context context;
////////////////////////////////////////////////////////////////////////////////
Sequence::Sequence ()
{
}
////////////////////////////////////////////////////////////////////////////////
Sequence::Sequence (const std::string& input)
{
parse (input);
}
////////////////////////////////////////////////////////////////////////////////
Sequence::~Sequence ()
{
}
////////////////////////////////////////////////////////////////////////////////
bool Sequence::valid (const std::string& input) const
{
std::vector <std::string> ranges;
split (ranges, input, ',');
std::vector <std::string>::iterator it;
for (it = ranges.begin (); it != ranges.end (); ++it)
{
std::vector <std::string> range;
split (range, *it, '-');
if (range.size () < 1 ||
range.size () > 2)
return false;
if (range.size () <= 2 && !validId (range[0]))
return false;
if (range.size () == 2 && !validId (range[1]))
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
void Sequence::parse (const std::string& input)
{
std::vector <std::string> ranges;
split (ranges, input, ',');
std::vector <std::string>::iterator it;
for (it = ranges.begin (); it != ranges.end (); ++it)
{
std::vector <std::string> range;
split (range, *it, '-');
switch (range.size ())
{
case 1:
{
if (! validId (range[0]))
throw context.stringtable.get (SEQUENCE_BAD_SEQ, "Invalid ID in sequence");
int id = ::atoi (range[0].c_str ());
this->push_back (id);
}
break;
case 2:
{
if (! validId (range[0]) ||
! validId (range[1]))
throw context.stringtable.get (SEQUENCE_BAD_SEQ, "Invalid ID in range");
int low = ::atoi (range[0].c_str ());
int high = ::atoi (range[1].c_str ());
if (low > high)
throw context.stringtable.get (SEQUENCE_INVERTED, "Inverted sequence range high-low");
if (high - low >= SEQUENCE_MAX)
throw context.stringtable.get (SEQUENCE_RANGE_MAX, "ID Range too large");
for (int i = low; i <= high; ++i)
this->push_back (i);
}
break;
default:
throw context.stringtable.get (SEQUENCE_NOT_A_SEQUENCE, "Not a sequence.");
break;
}
}
}
////////////////////////////////////////////////////////////////////////////////
void Sequence::combine (const Sequence& other)
{
// Create a map using the sequence elements as keys. This will create a
// unique list, with no duplicates.
std::map <int, int> both;
foreach (i, *this) both[*i] = 0;
foreach (i, other) both[*i] = 0;
// Now make a sequence out of the keys of the map.
this->clear ();
foreach (i, both)
this->push_back (i->first);
std::sort (this->begin (), this->end ());
}
////////////////////////////////////////////////////////////////////////////////
bool Sequence::validId (const std::string& input) const
{
if (input.length () == 0)
return false;
for (size_t i = 0; i < input.length (); ++i)
if (!::isdigit (input[i]))
return false;
return true;
}
////////////////////////////////////////////////////////////////////////////////

51
src/Sequence.h Normal file
View file

@ -0,0 +1,51 @@
////////////////////////////////////////////////////////////////////////////////
// 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_SEQUENCE
#define INCLUDED_SEQUENCE
#include <vector>
#include <string>
#define SEQUENCE_MAX 1000
class Sequence : public std::vector <int>
{
public:
Sequence (); // Default constructor
Sequence (const std::string&); // Parse
~Sequence (); // Destructor
bool valid (const std::string&) const;
void parse (const std::string&);
void combine (const Sequence&);
private:
bool validId (const std::string&) const;
};
#endif
////////////////////////////////////////////////////////////////////////////////

98
src/StringTable.cpp Normal file
View file

@ -0,0 +1,98 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#include <fstream>
#include <sstream>
#include <text.h>
#include <util.h>
#include <stdlib.h>
#include "StringTable.h"
////////////////////////////////////////////////////////////////////////////////
StringTable::StringTable ()
{
}
////////////////////////////////////////////////////////////////////////////////
StringTable::~StringTable ()
{
}
////////////////////////////////////////////////////////////////////////////////
// UTF-8 encoding
//
// 123 This is the string
// 124 This is another string
// ...
void StringTable::load (const std::string& file)
{
this->clear (); // Allows dynamic reload.
std::ifstream in;
in.open (file.c_str (), std::ifstream::in);
if (in.good ())
{
std::string line;
while (getline (in, line))
{
// Remove comments.
std::string::size_type pound = line.find ("#"); // no i18n
if (pound != std::string::npos)
line = line.substr (0, pound);
line = trim (line, " \t"); // no i18n
// Skip empty lines.
if (line.length () > 0)
{
std::string::size_type equal = line.find (" "); // no i18n
if (equal != std::string::npos)
{
int key = ::atoi (trim (line.substr (0, equal), " \t").c_str ()); // no i18n
std::string value = trim (line.substr (equal+1, line.length () - equal), " \t"); // no i18n
(*this)[key] = value;
}
}
}
in.close ();
}
else
throw std::string ("Could not read string file '") + file + "'"; // TODO i18n
}
////////////////////////////////////////////////////////////////////////////////
std::string StringTable::get (int id, const std::string& alternate)
{
// Return the right string.
if (this->find (id) != this->end ())
return (*this)[id];
return alternate;
}
////////////////////////////////////////////////////////////////////////////////

Some files were not shown because too many files have changed in this diff Show more