mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
Merge branch '1.9.0' into hooks
This commit is contained in:
commit
31055360dc
56 changed files with 1271 additions and 1316 deletions
2
AUTHORS
2
AUTHORS
|
@ -3,6 +3,7 @@ The development of task was made possible by the significant contributions of th
|
|||
Federico Hernandez (Package Maintainer & Contributing Author)
|
||||
David J Patrick (Designer)
|
||||
John Florian (Contributing Author)
|
||||
Cory Donnelly (Contributing Author)
|
||||
|
||||
The following submitted code, packages or analysis, and deserve special thanks:
|
||||
Damian Glenny
|
||||
|
@ -18,7 +19,6 @@ The following submitted code, packages or analysis, and deserve special thanks:
|
|||
Johan Friis
|
||||
Steven de Brouwer
|
||||
Pietro Cerutti
|
||||
Cory Donnelly
|
||||
|
||||
Thanks to the following, who submitted detailed bug reports and excellent suggestions:
|
||||
Eugene Kramer
|
||||
|
|
12
ChangeLog
12
ChangeLog
|
@ -2,6 +2,11 @@
|
|||
------ current release ---------------------------
|
||||
|
||||
1.9.0 ()
|
||||
+ Added feature #283 that makes it possible to control the verbosity
|
||||
of the output of annotations.
|
||||
+ Added feature #254 (#295) which gives task a second date format to be
|
||||
used in the reports with more conversion sequences like weekday name
|
||||
or weeknumber. The date format is set with variable "reportdateformat".
|
||||
+ Added feature #292 that permits alternate line coloration in reports
|
||||
(thanks to Richard Querin).
|
||||
+ Added feature #307 that provides vim with syntax highlighting for .taskrc.
|
||||
|
@ -19,8 +24,11 @@
|
|||
+ Added new 'config' command to display the configuration settings of task.
|
||||
As a consequence 'version' now only shows the version number and legal
|
||||
information.
|
||||
+ The 'config' command now complains about use of deprecated color names and
|
||||
duplicate entries in .taskrc.
|
||||
+ The 'config' command now complains about use of deprecated color names in
|
||||
your .taskrc file.
|
||||
+ Added feature #296, that allows the 'config' command to modify your .taskrc
|
||||
settings directly, with the command 'task config <name> <value>', or
|
||||
'task config <name>' to remove the setting.
|
||||
+ Task now supports nested .taskrc files using the "include /path" directive.
|
||||
+ The 'entry', 'start' and 'end' columns now have equivalents that include the
|
||||
time, and are called 'entry_time', 'start_time', and 'end_time', for use in
|
||||
|
|
|
@ -14,7 +14,7 @@ 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
|
||||
nobase_dist_vimscripts_DATA = scripts/vim/README scripts/vim/ftdetect/task.vim scripts/vim/syntax/taskdata.vim scripts/vim/syntax/taskedit.vim scripts/vim/syntax/taskrc.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
|
||||
|
|
1
NEWS
1
NEWS
|
@ -7,6 +7,7 @@ New Features in task 1.9
|
|||
- Supports nested .taskrc files with the new "include" statement"
|
||||
- New columns that include the time as well as date
|
||||
- New attribute modifiers
|
||||
- New date format for reports
|
||||
- Improved .taskrc validation
|
||||
- Improved calendar report with custom coloring and optional task details output
|
||||
|
||||
|
|
|
@ -1,24 +1,32 @@
|
|||
.TH task-faq 5 2010-01-03 "task 1.9.0" "User Manuals"
|
||||
|
||||
.SH NAME
|
||||
task-faq \- A FAQ 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 commands that allow you to do various things with it.
|
||||
|
||||
.SH WELCOME
|
||||
Welcome to the task FAQ. If you have would like to see a question answered
|
||||
here, please send us a note at <support@taskwarrior.org>.
|
||||
|
||||
.TP
|
||||
.B Where does task store the data?
|
||||
.B Q: Where does task store the data?
|
||||
By default, task creates a .taskrc file in your home directory and populates it
|
||||
with defaults. Task also creates a .task directory in your home directory and
|
||||
puts data files there.
|
||||
|
||||
.TP
|
||||
.B Can I edit that data?
|
||||
.B Q: Can I edit that data?
|
||||
Of course you can. It is a simple text file, and looks somewhat like the JSON
|
||||
format, and if you are careful not to break the format, there is no reason not
|
||||
to edit it. But task provides a rich command set to do that manipulation for
|
||||
you, so it is probably best to leave those files alone.
|
||||
|
||||
.TP
|
||||
.B How do I restore my .taskrc file to defaults?
|
||||
.B Q: How do I restore my .taskrc file to defaults?
|
||||
If you delete (or rename) your .taskrc file, task will offer to create a default
|
||||
one for you. Another way to do this is with the command:
|
||||
|
||||
|
@ -28,14 +36,51 @@ Task will create 'new-file' if it doesn't already exist. Note that this is a
|
|||
good way to learn about new configuration settings, if your .taskrc file was
|
||||
created by an older version of task.
|
||||
|
||||
.TP
|
||||
.B Q: Do I need to back up my task data?
|
||||
Yes. You should back up your ~/.task directory, and probably your ~/.taskrc
|
||||
file too.
|
||||
|
||||
.TP
|
||||
.B Q: Can I share my tasks between different machines?
|
||||
|
||||
.TP
|
||||
.B Q: The undo.data file gets very large - do I need it?
|
||||
You need it if you want the undo capability. But if it gets large, you can
|
||||
certainly truncate it to save space, just be careful to delete lines from the
|
||||
top of the file, up to and including a separator '---'. Note that it does not
|
||||
slow down task, because task never reads it until you want to undo. Otherwise
|
||||
task only appends to the file.
|
||||
|
||||
.TP
|
||||
.B Q: How do I know whether my terminal support 256 colors?
|
||||
The easiest way is to just try it! With task 1.9 or later, you simply run
|
||||
|
||||
$ task color
|
||||
|
||||
and a full color palette is displayed, if you look at it and see lots of
|
||||
different colors, then your terminal supports 256 colors. If you see only
|
||||
8 or 16 colors, many of them repeated, with blank areas then your terminal
|
||||
does not support 256 colors. xterm does. iTerm does.
|
||||
|
||||
.TP
|
||||
.B Q: How can I make task put the command in the terminal window title?
|
||||
You cannot. But you can make the shell do it, and you can make the shell
|
||||
call the task program. Here is a Bash script that does this:
|
||||
|
||||
#! /bin/bash
|
||||
|
||||
printf "\033]0;task $*\a"
|
||||
/usr/local/bin/task $*
|
||||
|
||||
You just need to run the script, and let the script run task. Here is a Bash
|
||||
function that does the same thing:
|
||||
|
||||
t ()
|
||||
{
|
||||
printf "\033]0;task $*\a"
|
||||
/usr/local/bin/task $*
|
||||
}
|
||||
|
||||
.SH "CREDITS & COPYRIGHTS"
|
||||
task was written by P. Beckingham <paul@beckingham.net>.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.TH task-tutorial 5 2009-09-07 "task 1.9.0" "User Manuals"
|
||||
.TH task-tutorial 5 2010-01-03 "task 1.9.0" "User Manuals"
|
||||
|
||||
.SH NAME
|
||||
task-tutorial \- A tutorial for the task(1) command line todo manager.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.TH task 1 2009-09-07 "task 1.9.0" "User Manuals"
|
||||
.TH task 1 2010-01-03 "task 1.9.0" "User Manuals"
|
||||
|
||||
.SH NAME
|
||||
task \- A command line todo manager.
|
||||
|
@ -129,8 +129,22 @@ Displays all possible colors, or a sample.
|
|||
Shows the task version number
|
||||
|
||||
.TP
|
||||
.B config
|
||||
Shows the current settings in the task configuration file.
|
||||
.B config [name [value | '']]
|
||||
Shows the current settings in the task configuration file. Also supports
|
||||
directly modifying the .taskrc file. This command either modifies
|
||||
the 'name' setting with a new value of 'value', or adds a new entry that
|
||||
is equivalent to 'name=value':
|
||||
|
||||
task config name value
|
||||
|
||||
This command sets a blank value. This has the effect of suppressing any
|
||||
default value:
|
||||
|
||||
task config name ''
|
||||
|
||||
Finally, this command removes any 'name=...' entry from the .taskrc file:
|
||||
|
||||
task config name
|
||||
|
||||
.TP
|
||||
.B help
|
||||
|
@ -157,9 +171,13 @@ Shows all tasks matching the specified criteria
|
|||
that are completed.
|
||||
|
||||
.TP
|
||||
.B ls [tags] [attrs] [description]
|
||||
.B minimal [tags] [attrs] [description]
|
||||
Provides a minimal listing of tasks with specified criteria.
|
||||
|
||||
.TP
|
||||
.B ls [tags] [attrs] [description]
|
||||
Provides a short listing of tasks with specified criteria.
|
||||
|
||||
.TP
|
||||
.B list [tags] [attrs] [description]
|
||||
Provides a more detailed listing of tasks with specified criteria.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.TH taskrc 5 2009-09-07 "task 1.9.0" "User Manuals"
|
||||
.TH taskrc 5 2010-01-03 "task 1.9.0" "User Manuals"
|
||||
|
||||
.SH NAME
|
||||
taskrc \- Configuration file for the task(1) command
|
||||
|
@ -115,6 +115,10 @@ May be "yes" or "no", and determines whether task will ask for confirmation befo
|
|||
.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 or delete commands. The default value is "yes".
|
||||
|
||||
.TP
|
||||
.B annotation.details=2
|
||||
Controls the output of annotations in reports. Defaults to 2 - all annotations are displayed. Set to 1 only the last (youngest) annotation is displayed and if there are more than one present for a task a "+" sign is added to the description. Set to 0 the output of annotations is disabled and a "+" sign will be added if there are any annotations present.
|
||||
|
||||
.TP
|
||||
.B next=2
|
||||
Is a number, defaulting to 2, which is the number of tasks for each project that are shown in the
|
||||
|
@ -148,33 +152,59 @@ tag names you have used, or just the ones used in active tasks.
|
|||
|
||||
.TP
|
||||
.B dateformat=m/d/Y
|
||||
This is a string of characters that define how task formats dates. The default value is: m/d/Y.
|
||||
The string should contain the characters
|
||||
.TP
|
||||
.B reportdateformat=m/d/Y
|
||||
This is a string of characters that define how task formats dates. If
|
||||
.B reportdateformat
|
||||
is set it will be used for the due date in the output of reports and "task info".
|
||||
|
||||
The default value is: m/d/Y. The string should contain the characters
|
||||
|
||||
.RS
|
||||
m minimal-digit month, for example 1 or 12
|
||||
m minimal-digit month, for example 1 or 12
|
||||
.br
|
||||
d minimal-digit day, for example 1 or 30
|
||||
d minimal-digit day, for example 1 or 30
|
||||
.br
|
||||
y two-digit year, for example 09
|
||||
y two-digit year, for example 09
|
||||
.br
|
||||
D two-digit day, for example 01 or 30
|
||||
D two-digit day, for example 01 or 30
|
||||
.br
|
||||
M two-digit month, for example 01 or 12
|
||||
M two-digit month, for example 01 or 12
|
||||
.br
|
||||
Y four-digit year, for example 2009
|
||||
Y four-digit year, for example 2009
|
||||
.br
|
||||
a short name of weekday, for example Mon or Wed
|
||||
.br
|
||||
A long name of weekday, for example Monday or Wednesday
|
||||
.br
|
||||
b short name of month, for example Jan or Aug
|
||||
.br
|
||||
B long name of month, for example January or August
|
||||
.br
|
||||
V weeknumber, for example 03 or 37
|
||||
.RE
|
||||
|
||||
The string may also contain other characters to act as spacers, or formatting. Examples for other
|
||||
variable values:
|
||||
values of dateformat:
|
||||
|
||||
.RS
|
||||
.br
|
||||
d/m/Y would output 24/7/2009
|
||||
d/m/Y would use for input and output 24/7/2009
|
||||
.br
|
||||
YMD would output 20090724
|
||||
yMD would use for input and output 090724
|
||||
.br
|
||||
m-d-y would output 07-24-09
|
||||
M-D-Y would use for input and output 07-24-2009
|
||||
.RE
|
||||
|
||||
Examples for other values of reportdateformat:
|
||||
|
||||
.RS
|
||||
.br
|
||||
a D b Y (V) would do an output as "Fri 24 Jul 2009 (30)"
|
||||
.br
|
||||
A, B D, Y would do an output as "Friday, July 24, 2009"
|
||||
.br
|
||||
vV a Y-M-D would do an output as "v30 Fri 2009-07.24"
|
||||
.RE
|
||||
|
||||
.TP
|
||||
|
|
34
doc/misc/script-color.txt
Normal file
34
doc/misc/script-color.txt
Normal file
|
@ -0,0 +1,34 @@
|
|||
Hello. This is a demonstration of the
|
||||
task program color capabilities coming
|
||||
in version 1.9.
|
||||
|
||||
task color The color command shows the various
|
||||
supported colors. For this you will
|
||||
need an xterm with 256-color support,
|
||||
or an equivalent.
|
||||
|
||||
This demo uses iTerm running on Snow
|
||||
Leopard.
|
||||
|
||||
task add Prepare 1.9 for release Let's create a few tasks, to illustrate
|
||||
task add Update the various docs the features. Five should be enough.
|
||||
task add Run the regression tests
|
||||
task add Make the packages
|
||||
task add Upload to distributions
|
||||
|
||||
--- NOTES
|
||||
|
||||
16-color mode
|
||||
upgrade
|
||||
blending
|
||||
alternate lines
|
||||
|
||||
--- NOTES
|
||||
|
||||
task ls Okay, let's color any tasks that
|
||||
mention tests a nice medium blue.
|
||||
|
||||
echo 'color.keyword.test=color23' >> ~/.taskrc
|
||||
|
||||
|
||||
|
1
doc/rc/dark-16.theme
Normal file
1
doc/rc/dark-16.theme
Normal file
|
@ -0,0 +1 @@
|
|||
# Sample task 1.9 (or later) color theme
|
1
doc/rc/dark-256.theme
Normal file
1
doc/rc/dark-256.theme
Normal file
|
@ -0,0 +1 @@
|
|||
# Sample task 1.9 (or later) color theme
|
1
doc/rc/light-16.theme
Normal file
1
doc/rc/light-16.theme
Normal file
|
@ -0,0 +1 @@
|
|||
# Sample task 1.9 (or later) color theme
|
1
doc/rc/light-256.theme
Normal file
1
doc/rc/light-256.theme
Normal file
|
@ -0,0 +1 @@
|
|||
# Sample task 1.9 (or later) color theme
|
|
@ -1,281 +0,0 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
|
||||
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.
|
||||
|
||||
---
|
|
@ -331,7 +331,7 @@ bool Att::validNameValue (
|
|||
{
|
||||
// Validate and convert to epoch.
|
||||
if (value != "")
|
||||
value = Date (value, context.config.get ("dateformat", "m/d/Y")).toEpochString ();
|
||||
value = Date (value, context.config.get ("dateformat")).toEpochString ();
|
||||
}
|
||||
|
||||
else if (name == "recur")
|
||||
|
@ -571,7 +571,7 @@ bool Att::match (const Att& other) const
|
|||
}
|
||||
else if (which == "date")
|
||||
{
|
||||
Date literal (mValue.c_str (), context.config.get ("dateformat", "m/d/Y"));
|
||||
Date literal (mValue.c_str (), context.config.get ("dateformat"));
|
||||
Date variable ((time_t)atoi (other.mValue.c_str ()));
|
||||
if (other.mValue == "" || ! (variable < literal))
|
||||
return false;
|
||||
|
@ -601,7 +601,7 @@ bool Att::match (const Att& other) const
|
|||
}
|
||||
else if (which == "date")
|
||||
{
|
||||
Date literal (mValue.c_str (), context.config.get ("dateformat", "m/d/Y"));
|
||||
Date literal (mValue.c_str (), context.config.get ("dateformat"));
|
||||
Date variable ((time_t)atoi (other.mValue.c_str ()));
|
||||
if (! (variable > literal))
|
||||
return false;
|
||||
|
|
686
src/Config.cpp
686
src/Config.cpp
|
@ -27,30 +27,231 @@
|
|||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <pwd.h>
|
||||
#include "Directory.h"
|
||||
#include "File.h"
|
||||
#include "Config.h"
|
||||
#include "text.h"
|
||||
#include "util.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// These are default (but overridable) reports. These entries are necessary
|
||||
// because these three reports were converted from hard-coded reports to custom
|
||||
// reports, and therefore need these config file entries. However, users are
|
||||
// already used to seeing these five reports, but do not have these entries.
|
||||
// The choice was a) make users edit their .taskrc files, b) write a .taskrc
|
||||
// upgrade program to make the change, or c) this.
|
||||
// This string is used in two ways:
|
||||
// 1) It is used to create a new .taskrc file, by copying it directly to disk.
|
||||
// 2) It is parsed and used as default values for all Config.get calls.
|
||||
std::string Config::defaults =
|
||||
"# Task program configuration file.\n"
|
||||
"# For more documentation, see http://taskwarrior.org or try 'man task' and 'man taskrc'\n"
|
||||
"\n"
|
||||
"# Files\n"
|
||||
"data.location=~/.task\n"
|
||||
"locking=on # Use file-level locking\n"
|
||||
"\n"
|
||||
"# Terminal\n"
|
||||
"curses=on # Use ncurses library to determine terminal width\n"
|
||||
"defaultwidth=80 # Without ncurses, assumed width\n"
|
||||
"#editor=vi # Preferred text editor\n"
|
||||
"\n"
|
||||
"# Miscellaneous\n"
|
||||
"confirmation=yes # Confirmation on delete, big changes\n"
|
||||
"echo.command=yes # Details on command just run\n"
|
||||
"annotation.details=2 # Level of verbosity for annotations in reports\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" // TODO
|
||||
"\n"
|
||||
"# Dates\n"
|
||||
"dateformat=m/d/Y # Preferred input and display date format\n"
|
||||
"#reportdateformat=m/d/Y # Preferred display date format for repors\n"
|
||||
"weekstart=Sunday # Sunday or Monday only\n" // TODO
|
||||
"displayweeknumber=yes # Show week numbers on calendar\n" // TODO
|
||||
"due=7 # Task is considered due in 7 days\n"
|
||||
"#calendar.details=yes # Calendar shows information for tasks w/due dates\n"
|
||||
"#calendar.details.report=list # Report to use when showing task information in cal\n" // TODO
|
||||
"#monthsperline=3 # Number of calendar months on a line\n" // TODO
|
||||
"\n"
|
||||
"# Color controls.\n"
|
||||
"color=on # Enable 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"
|
||||
"#color.alternate=on rgb253 # Alternate color for line coloring\n"
|
||||
"color.calendar.today=black on cyan # Color of today in calendar\n"
|
||||
"color.calendar.due=black on green # Color of days with due tasks in calendar\n"
|
||||
"color.calendar.overdue=black on red # Color of days with overdue tasks in calendar\n"
|
||||
"color.calendar.weekend=black on white # Color of weekend days in calendar\n"
|
||||
"#color.debug=magenta # Color of diagnostic output\n"
|
||||
"color.pri.H=bold # Color of priority:H tasks\n"
|
||||
"color.history.add=on red # Color of added tasks in the history reports\n"
|
||||
"color.history.delete=on yellow # Color of deleted tasks in the history reports\n"
|
||||
"color.history.done=on green # Color of completed tasks in the history reports\n"
|
||||
"\n"
|
||||
"# Shadow file support\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 # Default project for 'add' command\n"
|
||||
"#default.priority=M # Default priority for 'add' command\n"
|
||||
"default.command=list # When no arguments are specified\n" // TODO
|
||||
"\n"
|
||||
"_forcecolor=no # Forces color to be on, even for non TTY output\n"
|
||||
"blanklines=true # Use more whitespace in output\n"
|
||||
"complete.all.projects=no # Include old project names in 'projects' command\n" // TODO
|
||||
"complete.all.tags=no # Include old tag names in 'tags' command\n" // TODO
|
||||
"debug=no # Display diagnostics\n"
|
||||
"fontunderline=yes # Uses underlines rather than -------\n"
|
||||
"shell.prompt=task> # Prompt used by the shell command\n" // TODO
|
||||
"\n"
|
||||
"# Import heuristics - alternate names for fields (comma-separated list of names)\n"
|
||||
"#import.synonym.bg=?\n"
|
||||
"#import.synonym.description=?\n"
|
||||
"#import.synonym.due=?\n"
|
||||
"#import.synonym.end=?\n"
|
||||
"#import.synonym.entry=?\n"
|
||||
"#import.synonym.fg=?\n"
|
||||
"#import.synonym.id=?\n"
|
||||
"#import.synonym.priority=?\n"
|
||||
"#import.synonym.project=?\n"
|
||||
"#import.synonym.recur=?\n"
|
||||
"#import.synonym.start=?\n"
|
||||
"#import.synonym.status=?\n"
|
||||
"#import.synonym.tags=?\n"
|
||||
"#import.synonym.uuid=?\n"
|
||||
"\n"
|
||||
"# Aliases - alternate names for commands\n"
|
||||
"alias.rm=delete # Alias for the delete command\n"
|
||||
"\n"
|
||||
"# Fields: id,uuid,project,priority,priority_long,entry,entry_time,\n" // TODO
|
||||
"# start,entry_time,due,recur,recurrence_indicator,age,\n" // TODO
|
||||
"# age_compact,active,tags,tag_indicator,description,\n" // TODO
|
||||
"# description_only,end,end_time\n" // TODO
|
||||
"# 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 minimal\n"
|
||||
"report.minimal.description=A really minimal listing\n"
|
||||
"report.minimal.columns=id,project,description\n"
|
||||
"report.minimal.labels=ID,Project,Description\n"
|
||||
"report.minimal.sort=project+,description+\n"
|
||||
"report.minimal.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";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// DO NOT CALL Config::setDefaults.
|
||||
//
|
||||
// This is a default constructor, and as such is only used to:
|
||||
// a) initialize a default Context constructor
|
||||
// b) run unit tests
|
||||
//
|
||||
// In all real use cases, Config::load is called.
|
||||
Config::Config ()
|
||||
{
|
||||
setDefaults ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Config::Config (const std::string& file)
|
||||
{
|
||||
setDefaults ();
|
||||
load (file);
|
||||
}
|
||||
|
||||
|
@ -62,346 +263,117 @@ Config::Config (const std::string& file)
|
|||
// Nested files are now supported, with the following construct:
|
||||
// include /absolute/path/to/file
|
||||
//
|
||||
bool Config::load (const std::string& file, int nest /* = 1 */)
|
||||
void Config::load (const std::string& file, int nest /* = 1 */)
|
||||
{
|
||||
if (nest > 10)
|
||||
throw std::string ("Configuration file nested to more than 10 levels deep"
|
||||
" - this has to be a mistake.");
|
||||
|
||||
std::ifstream in;
|
||||
in.open (file.c_str (), std::ifstream::in);
|
||||
if (in.good ())
|
||||
// First time in, load the default values.
|
||||
if (nest == 1)
|
||||
{
|
||||
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)
|
||||
{
|
||||
std::string key = trim (line.substr (0, equal), " \t"); // no i18n
|
||||
std::string value = trim (line.substr (equal+1, line.length () - equal), " \t"); // no i18n
|
||||
|
||||
(*this)[key] = value;
|
||||
sequence.push_back (key);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string::size_type include = line.find ("include"); // no i18n.
|
||||
if (include != std::string::npos)
|
||||
{
|
||||
std::string included = expandPath ( trim ( line.substr (include + 7), " \t"));
|
||||
if (isAbsolutePath (included))
|
||||
{
|
||||
if (!access (included.c_str (), F_OK | R_OK))
|
||||
this->load (included, nest + 1);
|
||||
else
|
||||
throw std::string ("Could not read include file '") + included + "'";
|
||||
}
|
||||
else
|
||||
throw std::string ("Can only include files with absolute paths, not '") + included + "'";
|
||||
}
|
||||
else
|
||||
throw std::string ("Malformed entry in ") + file + ": '" + line + "'";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in.close ();
|
||||
return true;
|
||||
setDefaults ();
|
||||
original_file = File (file);
|
||||
}
|
||||
|
||||
return false;
|
||||
// Read the file, then parse the contents.
|
||||
std::string contents;
|
||||
if (File::read (file, contents) && contents.length ())
|
||||
parse (contents, nest);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Config::parse (const std::string& input, int nest /* = 1 */)
|
||||
{
|
||||
// Shortcut case for default constructor.
|
||||
if (input.length () == 0)
|
||||
return;
|
||||
|
||||
// Split the input into lines.
|
||||
std::vector <std::string> lines;
|
||||
split (lines, input, "\n");
|
||||
|
||||
// Parse each line.
|
||||
std::vector <std::string>::iterator it;
|
||||
for (it = lines.begin (); it != lines.end (); ++it)
|
||||
{
|
||||
std::string line = *it;
|
||||
|
||||
// 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)
|
||||
{
|
||||
std::string key = trim (line.substr (0, equal), " \t"); // no i18n
|
||||
std::string value = trim (line.substr (equal+1, line.length () - equal), " \t"); // no i18n
|
||||
|
||||
(*this)[key] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string::size_type include = line.find ("include"); // no i18n.
|
||||
if (include != std::string::npos)
|
||||
{
|
||||
Path included (trim (line.substr (include + 7), " \t"));
|
||||
if (included.is_absolute ())
|
||||
{
|
||||
if (included.readable ())
|
||||
this->load (included, nest + 1);
|
||||
else
|
||||
throw std::string ("Could not read include file '") + included.data + "'";
|
||||
}
|
||||
else
|
||||
throw std::string ("Can only include files with absolute paths, not '") + included.data + "'";
|
||||
}
|
||||
else
|
||||
throw std::string ("Malformed entry '") + line + "'";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Config::createDefaultRC (const std::string& rc, const std::string& data)
|
||||
{
|
||||
// Create a sample .taskrc file.
|
||||
std::stringstream contents;
|
||||
contents << "# Task program configuration file.\n"
|
||||
<< "# For more documentation, see http://taskwarrior.org or try 'man task' and 'man taskrc'\n"
|
||||
<< "\n"
|
||||
<< "# Files\n"
|
||||
<< "data.location=" << data << "\n"
|
||||
<< "locking=on # Use file-level locking\n"
|
||||
<< "\n"
|
||||
<< "# Terminal\n"
|
||||
<< "curses=on # Use ncurses library to determine terminal width\n"
|
||||
<< "#defaultwidth=80 # Without ncurses, assumed width\n"
|
||||
<< "#editor=vi # Preferred text editor\n"
|
||||
<< "\n"
|
||||
<< "# Miscellaneous\n"
|
||||
<< "confirmation=yes # Confirmation on delete, big changes\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"
|
||||
<< "#calendar.details=yes # Calendar shows information for tasks w/due dates\n"
|
||||
<< "#calendar.details.report=list # Report to use when showing task information in cal\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"
|
||||
<< "#color.alternate=on_rgb253 # Alternate color for line coloring\n"
|
||||
<< "color.calendar.today=black on cyan # Color of today in calendar\n"
|
||||
<< "color.calendar.due=black on green # Color of days with due tasks in calendar\n"
|
||||
<< "color.calendar.overdue=black on red # Color of days with overdue tasks in calendar\n"
|
||||
<< "color.calendar.weekend=black on white # Color of weekend days in calendar\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"
|
||||
<< "alias.rm=delete\n"
|
||||
<< "\n"
|
||||
<< "# Fields: id,uuid,project,priority,priority_long,entry,entry_time,\n"
|
||||
<< "# start,entry_time,due,recur,recurrence_indicator,age,\n"
|
||||
<< "# age_compact,active,tags,tag_indicator,description,\n"
|
||||
<< "# description_only,end,end_time\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 minimal\n"
|
||||
<< "report.minimal.description=A really minimal listing\n"
|
||||
<< "report.minimal.columns=id,project,description\n"
|
||||
<< "report.minimal.labels=ID,Project,Description\n"
|
||||
<< "report.minimal.sort=project+,description+\n"
|
||||
<< "report.minimal.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";
|
||||
// Override data.location in the defaults.
|
||||
std::string::size_type loc = defaults.find ("data.location=~/.task");
|
||||
// loc+0^ +14^ +21^
|
||||
|
||||
spit (rc, contents.str ());
|
||||
std::string contents = defaults.substr (0, loc + 14) +
|
||||
data +
|
||||
defaults.substr (loc + 21, std::string::npos);
|
||||
|
||||
// Write out the new file.
|
||||
if (! File::write (rc, contents))
|
||||
throw std::string ("Could not write to '") + rc + "'";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Config::createDefaultData (const std::string& data)
|
||||
{
|
||||
if (access (data.c_str (), F_OK))
|
||||
mkdir (data.c_str (), S_IRWXU);
|
||||
Directory d (data);
|
||||
if (! d.exists ())
|
||||
d.create ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Config::setDefaults ()
|
||||
{
|
||||
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
|
||||
|
||||
set ("report.list.description", "Lists all tasks matching the specified criteria"); // TODO i18n
|
||||
set ("report.list.columns", "id,project,priority,due,active,age,description"); // TODO i18n
|
||||
set ("report.list.labels", "ID,Project,Pri,Due,Active,Age,Description"); // TODO i18n
|
||||
set ("report.list.sort", "due+,priority-,project+"); // TODO i18n
|
||||
set ("report.list.filter", "status:pending"); // TODO i18n
|
||||
|
||||
set ("report.ls.description", "Short listing of all tasks matching the specified criteria"); // TODO i18n
|
||||
set ("report.ls.columns", "id,project,priority,description"); // TODO i18n
|
||||
set ("report.ls.labels", "ID,Project,Pri,Description"); // TODO i18n
|
||||
set ("report.ls.sort", "priority-,project+"); // TODO i18n
|
||||
set ("report.ls.filter", "status:pending"); // TODO i18n
|
||||
|
||||
set ("report.minimal.description", "A really minimal listing"); // TODO i18n
|
||||
set ("report.minimal.columns", "id,project,description"); // TODO i18n
|
||||
set ("report.minimal.labels", "ID,Project,Description"); // TODO i18n
|
||||
set ("report.minimal.sort", "project+,description+"); // TODO i18n
|
||||
set ("report.minimal.filter", "status:pending"); // TODO i18n
|
||||
|
||||
set ("report.newest.description", "Shows the newest tasks"); // TODO i18n
|
||||
set ("report.newest.columns", "id,project,priority,due,active,age,description"); // TODO i18n
|
||||
set ("report.newest.labels", "ID,Project,Pri,Due,Active,Age,Description"); // TODO i18n
|
||||
set ("report.newest.sort", "id-"); // TODO i18n
|
||||
set ("report.newest.filter", "status:pending limit:10"); // TODO i18n
|
||||
|
||||
set ("report.oldest.description", "Shows the oldest tasks"); // TODO i18n
|
||||
set ("report.oldest.columns", "id,project,priority,due,active,age,description"); // TODO i18n
|
||||
set ("report.oldest.labels", "ID,Project,Pri,Due,Active,Age,Description"); // TODO i18n
|
||||
set ("report.oldest.sort", "id+"); // TODO i18n
|
||||
set ("report.oldest.filter", "status:pending limit:10"); // TODO i18n
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
set ("report.recurring.description", "Lists recurring tasks matching the specified criteria"); // TODO i18n
|
||||
set ("report.recurring.columns", "id,project,priority,due,recur,active,age,description"); // TODO i18n
|
||||
set ("report.recurring.labels", "ID,Project,Pri,Due,Recur,Active,Age,Description"); // TODO i18n
|
||||
set ("report.recurring.sort", "due+,priority-,project+"); // TODO i18n
|
||||
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
|
||||
|
||||
set ("alias.rm", "delete"); // TODO i18n
|
||||
parse (defaults);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Config::clear ()
|
||||
{
|
||||
std::map <std::string, std::string>::clear ();
|
||||
sequence.clear ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Return the configuration value given the specified key.
|
||||
const std::string Config::get (const char* key)
|
||||
{
|
||||
return this->get (std::string (key));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Return the configuration value given the specified key. If a default_value
|
||||
// is present, it will be the returned value in the event of a missing key.
|
||||
const std::string Config::get (
|
||||
const char* key,
|
||||
const char* default_value)
|
||||
{
|
||||
return this->get (std::string (key), std::string (default_value));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -412,56 +384,42 @@ const std::string Config::get (const std::string& key)
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Return the configuration value given the specified key. If a default_value
|
||||
// is present, it will be the returned value in the event of a missing key.
|
||||
const std::string Config::get (
|
||||
const std::string& key,
|
||||
const std::string& default_value)
|
||||
const int Config::getInteger (const std::string& key)
|
||||
{
|
||||
if ((*this).find (key) != (*this).end ())
|
||||
return (*this)[key];
|
||||
return atoi ((*this)[key].c_str ());
|
||||
|
||||
return default_value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Config::get (const std::string& key, const bool default_value)
|
||||
const double Config::getReal (const std::string& key)
|
||||
{
|
||||
if ((*this).find (key) != (*this).end ())
|
||||
return atof ((*this)[key].c_str ());
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
const bool Config::getBoolean (const std::string& key)
|
||||
{
|
||||
if ((*this).find (key) != (*this).end ())
|
||||
{
|
||||
std::string value = lowerCase ((*this)[key]);
|
||||
|
||||
if (value == "t" || // TODO i18n
|
||||
value == "true" || // TODO i18n
|
||||
value == "1" || // no i18n
|
||||
value == "+" || // no i18n
|
||||
value == "y" || // TODO i18n
|
||||
value == "yes" || // TODO i18n
|
||||
value == "on" || // TODO i18n
|
||||
value == "enable" || // TODO i18n
|
||||
value == "enabled") // TODO i18n
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return default_value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int Config::get (const std::string& key, const int default_value)
|
||||
{
|
||||
if ((*this).find (key) != (*this).end ())
|
||||
return atoi ((*this)[key].c_str ());
|
||||
|
||||
return default_value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
double Config::get (const std::string& key, const double default_value)
|
||||
{
|
||||
if ((*this).find (key) != (*this).end ())
|
||||
return atof ((*this)[key].c_str ());
|
||||
|
||||
return default_value;
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -494,40 +452,6 @@ void Config::all (std::vector<std::string>& items)
|
|||
items.push_back (i->first);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Config::getSequence (std::vector<std::string>& items)
|
||||
{
|
||||
items = sequence;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Config::checkForDuplicates ()
|
||||
{
|
||||
std::vector <std::string> duplicates;
|
||||
std::map <std::string, int> unique;
|
||||
|
||||
foreach (i, sequence)
|
||||
{
|
||||
if (unique.find (*i) != unique.end ())
|
||||
duplicates.push_back (*i);
|
||||
else
|
||||
unique[*i] = 0;
|
||||
}
|
||||
|
||||
std::stringstream out;
|
||||
if (duplicates.size ())
|
||||
{
|
||||
out << "Found duplicate entries for:" << std::endl;
|
||||
|
||||
foreach (i, duplicates)
|
||||
out << " " << *i << std::endl;
|
||||
|
||||
out << std::endl;
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Config::checkForDeprecatedColor ()
|
||||
{
|
||||
|
|
24
src/Config.h
24
src/Config.h
|
@ -30,6 +30,7 @@
|
|||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "File.h"
|
||||
|
||||
class Config : public std::map <std::string, std::string>
|
||||
{
|
||||
|
@ -40,30 +41,31 @@ public:
|
|||
Config (const Config&);
|
||||
Config& operator= (const Config&);
|
||||
|
||||
bool load (const std::string&, int nest = 1);
|
||||
void load (const std::string&, int nest = 1);
|
||||
void parse (const std::string&, int nest = 1);
|
||||
|
||||
void createDefaultRC (const std::string&, const std::string&);
|
||||
void createDefaultData (const std::string&);
|
||||
void setDefaults ();
|
||||
void clear ();
|
||||
|
||||
const std::string get (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&);
|
||||
bool get (const std::string&, const bool);
|
||||
int get (const std::string&, const int);
|
||||
double get (const std::string&, const double);
|
||||
const std::string get (const std::string&);
|
||||
const int getInteger (const std::string&);
|
||||
const double getReal (const std::string&);
|
||||
const bool getBoolean (const std::string&);
|
||||
|
||||
void set (const std::string&, const int);
|
||||
void set (const std::string&, const double);
|
||||
void set (const std::string&, const std::string&);
|
||||
void all (std::vector <std::string>&);
|
||||
void getSequence (std::vector<std::string>&);
|
||||
|
||||
std::string checkForDuplicates ();
|
||||
std::string checkForDeprecatedColor ();
|
||||
|
||||
public:
|
||||
File original_file;
|
||||
|
||||
private:
|
||||
std::vector <std::string> sequence;
|
||||
static std::string defaults;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "Context.h"
|
||||
#include "Directory.h"
|
||||
#include "File.h"
|
||||
#include "Timer.h"
|
||||
#include "text.h"
|
||||
#include "util.h"
|
||||
|
@ -98,16 +100,16 @@ void Context::initialize ()
|
|||
{
|
||||
config.set ("curses", "off");
|
||||
|
||||
if (! config.get (std::string ("_forcecolor"), false))
|
||||
if (! config.getBoolean ("_forcecolor"))
|
||||
config.set ("color", "off");
|
||||
}
|
||||
|
||||
if (config.get ("color", true))
|
||||
if (config.getBoolean ("color"))
|
||||
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"));
|
||||
Directory location (config.get ("data.location"));
|
||||
std::string locale = config.get ("locale");
|
||||
|
||||
// If there is a locale variant (en-US.<variant>), then strip it.
|
||||
|
@ -116,7 +118,7 @@ void Context::initialize ()
|
|||
locale = locale.substr (0, period);
|
||||
|
||||
if (locale != "")
|
||||
stringtable.load (location + "/strings." + locale);
|
||||
stringtable.load (location.data + "/strings." + locale);
|
||||
|
||||
// TODO Handle "--version, -v" right here?
|
||||
|
||||
|
@ -125,7 +127,7 @@ void Context::initialize ()
|
|||
std::vector <std::string> all;
|
||||
split (all, location, ',');
|
||||
foreach (path, all)
|
||||
tdb.location (expandPath (*path));
|
||||
tdb.location (*path);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -154,16 +156,16 @@ int Context::run ()
|
|||
}
|
||||
|
||||
// Dump all debug messages.
|
||||
if (config.get (std::string ("debug"), false))
|
||||
if (config.getBoolean ("debug"))
|
||||
foreach (d, debugMessages)
|
||||
if (config.get ("color", true) || config.get (std::string ("_forcecolor"), false))
|
||||
if (config.getBoolean ("color") || config.getBoolean ("_forcecolor"))
|
||||
std::cout << colorizeDebug (*d) << std::endl;
|
||||
else
|
||||
std::cout << *d << std::endl;
|
||||
|
||||
// Dump all headers.
|
||||
foreach (h, headers)
|
||||
if (config.get ("color", true) || config.get (std::string ("_forcecolor"), false))
|
||||
if (config.getBoolean ("color") || config.getBoolean ("_forcecolor"))
|
||||
std::cout << colorizeHeader (*h) << std::endl;
|
||||
else
|
||||
std::cout << *h << std::endl;
|
||||
|
@ -173,7 +175,7 @@ int Context::run ()
|
|||
|
||||
// Dump all footnotes.
|
||||
foreach (f, footnotes)
|
||||
if (config.get ("color", true) || config.get (std::string ("_forcecolor"), false))
|
||||
if (config.getBoolean ("color") || config.getBoolean ("_forcecolor"))
|
||||
std::cout << colorizeFootnote (*f) << std::endl;
|
||||
else
|
||||
std::cout << *f << std::endl;
|
||||
|
@ -244,8 +246,8 @@ int Context::dispatch (std::string &out)
|
|||
void Context::shadow ()
|
||||
{
|
||||
// Determine if shadow file is enabled.
|
||||
std::string shadowFile = expandPath (config.get ("shadow.file"));
|
||||
if (shadowFile != "")
|
||||
File shadowFile (config.get ("shadow.file"));
|
||||
if (shadowFile.data != "")
|
||||
{
|
||||
inShadow = true; // Prevents recursion in case shadow command writes.
|
||||
|
||||
|
@ -268,8 +270,10 @@ void Context::shadow ()
|
|||
|
||||
// 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"));
|
||||
std::string command = config.get ("shadow.command");
|
||||
if (command == "")
|
||||
command = config.get ("default.command");
|
||||
|
||||
split (args, command, ' ');
|
||||
|
||||
initialize ();
|
||||
|
@ -279,21 +283,21 @@ void Context::shadow ()
|
|||
parse ();
|
||||
std::string result;
|
||||
(void)dispatch (result);
|
||||
std::ofstream out (shadowFile.c_str ());
|
||||
std::ofstream out (shadowFile.data.c_str ());
|
||||
if (out.good ())
|
||||
{
|
||||
out << result;
|
||||
out.close ();
|
||||
}
|
||||
else
|
||||
throw std::string ("Could not write file '") + shadowFile + "'";
|
||||
throw std::string ("Could not write file '") + shadowFile.data + "'";
|
||||
|
||||
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]");
|
||||
if (config.getBoolean ("shadow.notify"))
|
||||
footnote (std::string ("[Shadow file '") + shadowFile.data + "' updated]");
|
||||
|
||||
inShadow = false;
|
||||
}
|
||||
|
@ -353,8 +357,10 @@ void Context::loadCorrectConfigFile ()
|
|||
"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";
|
||||
// std::string rc = home + "/.taskrc";
|
||||
// std::string data = home + "/.task";
|
||||
File rc (home + "/.taskrc");
|
||||
Directory data (home + "./task");
|
||||
|
||||
// Is there an file_override for rc:?
|
||||
foreach (arg, args)
|
||||
|
@ -364,28 +370,27 @@ void Context::loadCorrectConfigFile ()
|
|||
else if (arg->substr (0, 3) == "rc:")
|
||||
{
|
||||
file_override = *arg;
|
||||
rc = arg->substr (3);
|
||||
rc = File (arg->substr (3));
|
||||
|
||||
home = rc;
|
||||
std::string::size_type last_slash = rc.rfind ("/");
|
||||
std::string::size_type last_slash = rc.data.rfind ("/");
|
||||
if (last_slash != std::string::npos)
|
||||
home = rc.substr (0, last_slash);
|
||||
home = rc.data.substr (0, last_slash);
|
||||
else
|
||||
home = ".";
|
||||
|
||||
args.erase (arg);
|
||||
header ("Using alternate .taskrc file " + rc); // TODO i18n
|
||||
header ("Using alternate .taskrc file " + rc.data); // TODO i18n
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Load rc file.
|
||||
config.clear (); // Dump current values.
|
||||
config.setDefaults (); // Add in the custom reports.
|
||||
config.load (rc); // Load new file.
|
||||
config.load (rc); // Load new file.
|
||||
|
||||
if (config.get ("data.location") != "")
|
||||
data = config.get ("data.location");
|
||||
data = Directory (config.get ("data.location"));
|
||||
|
||||
// Are there any var_overrides for data.location?
|
||||
foreach (arg, args)
|
||||
|
@ -395,20 +400,20 @@ void Context::loadCorrectConfigFile ()
|
|||
else if (arg->substr (0, 17) == "rc.data.location:" ||
|
||||
arg->substr (0, 17) == "rc.data.location=")
|
||||
{
|
||||
data = arg->substr (17);
|
||||
header ("Using alternate data.location " + data); // TODO i18n
|
||||
data = Directory (arg->substr (17));
|
||||
header ("Using alternate data.location " + data.data); // TODO i18n
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Do we need to create a default rc?
|
||||
if (access (rc.c_str (), F_OK))
|
||||
if (! rc.exists ())
|
||||
{
|
||||
if (confirm ("A configuration file could not be found in " // TODO i18n
|
||||
+ home
|
||||
+ "\n\n"
|
||||
+ "Would you like a sample "
|
||||
+ rc
|
||||
+ rc.data
|
||||
+ " created, so task can proceed?"))
|
||||
{
|
||||
config.createDefaultRC (rc, data);
|
||||
|
@ -420,10 +425,11 @@ void Context::loadCorrectConfigFile ()
|
|||
// Create data location, if necessary.
|
||||
config.createDefaultData (data);
|
||||
|
||||
// TODO find out why this was done twice - see tw #355
|
||||
// Load rc file.
|
||||
config.clear (); // Dump current values.
|
||||
config.setDefaults (); // Add in the custom reports.
|
||||
config.load (rc); // Load new 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", or "rc.name=value".
|
||||
std::vector <std::string> filtered;
|
||||
|
|
140
src/Date.cpp
140
src/Date.cpp
|
@ -1,7 +1,7 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// task - a command line task list manager.
|
||||
//
|
||||
// Copyright 2006 - 2010, Paul Beckingham.
|
||||
// Copyright 2006 - 2010, Paul Beckingham, Federico Hernandez.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify it under
|
||||
|
@ -33,6 +33,9 @@
|
|||
#include "Date.h"
|
||||
#include "text.h"
|
||||
#include "util.h"
|
||||
#include "Context.h"
|
||||
|
||||
extern Context context;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Defaults to "now".
|
||||
|
@ -85,7 +88,7 @@ Date::Date (const std::string& mdy, const std::string& format /* = "m/d/Y" */)
|
|||
if (i >= mdy.length () ||
|
||||
! isdigit (mdy[i]))
|
||||
{
|
||||
throw std::string ("\"") + mdy + "\" is not a valid date.";
|
||||
throw std::string ("\"") + mdy + "\" is not a valid date (m).";
|
||||
}
|
||||
|
||||
if (i + 1 < mdy.length () &&
|
||||
|
@ -106,7 +109,7 @@ Date::Date (const std::string& mdy, const std::string& format /* = "m/d/Y" */)
|
|||
if (i >= mdy.length () ||
|
||||
! isdigit (mdy[i]))
|
||||
{
|
||||
throw std::string ("\"") + mdy + "\" is not a valid date.";
|
||||
throw std::string ("\"") + mdy + "\" is not a valid date (d).";
|
||||
}
|
||||
|
||||
if (i + 1 < mdy.length () &&
|
||||
|
@ -125,11 +128,11 @@ Date::Date (const std::string& mdy, const std::string& format /* = "m/d/Y" */)
|
|||
|
||||
// Double digit.
|
||||
case 'y':
|
||||
if (i + 1 >= mdy.length () ||
|
||||
if (i + 1 >= mdy.length () ||
|
||||
! isdigit (mdy[i + 0]) ||
|
||||
! isdigit (mdy[i + 1]))
|
||||
{
|
||||
throw std::string ("\"") + mdy + "\" is not a valid date.";
|
||||
throw std::string ("\"") + mdy + "\" is not a valid date (y).";
|
||||
}
|
||||
|
||||
year = atoi (mdy.substr (i, 2).c_str ()) + 2000;
|
||||
|
@ -141,7 +144,7 @@ Date::Date (const std::string& mdy, const std::string& format /* = "m/d/Y" */)
|
|||
! isdigit (mdy[i + 0]) ||
|
||||
! isdigit (mdy[i + 1]))
|
||||
{
|
||||
throw std::string ("\"") + mdy + "\" is not a valid date.";
|
||||
throw std::string ("\"") + mdy + "\" is not a valid date (M).";
|
||||
}
|
||||
|
||||
month = atoi (mdy.substr (i, 2).c_str ());
|
||||
|
@ -153,13 +156,24 @@ Date::Date (const std::string& mdy, const std::string& format /* = "m/d/Y" */)
|
|||
! isdigit (mdy[i + 0]) ||
|
||||
! isdigit (mdy[i + 1]))
|
||||
{
|
||||
throw std::string ("\"") + mdy + "\" is not a valid date.";
|
||||
throw std::string ("\"") + mdy + "\" is not a valid date (D).";
|
||||
}
|
||||
|
||||
day = atoi (mdy.substr (i, 2).c_str ());
|
||||
i += 2;
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
if (i + 1 >= mdy.length () ||
|
||||
! isdigit (mdy[i + 0]) ||
|
||||
! isdigit (mdy[i + 1]))
|
||||
{
|
||||
throw std::string ("\"") + mdy + "\" is not a valid date (V).";
|
||||
}
|
||||
|
||||
i += 2;
|
||||
break;
|
||||
|
||||
// Quadruple digit.
|
||||
case 'Y':
|
||||
if (i + 3 >= mdy.length () ||
|
||||
|
@ -168,18 +182,70 @@ Date::Date (const std::string& mdy, const std::string& format /* = "m/d/Y" */)
|
|||
! isdigit (mdy[i + 2]) ||
|
||||
! isdigit (mdy[i + 3]))
|
||||
{
|
||||
throw std::string ("\"") + mdy + "\" is not a valid date.";
|
||||
throw std::string ("\"") + mdy + "\" is not a valid date (Y).";
|
||||
}
|
||||
|
||||
year = atoi (mdy.substr (i, 4).c_str ());
|
||||
i += 4;
|
||||
break;
|
||||
|
||||
// Short names with 3 characters
|
||||
case 'a':
|
||||
if (i + 2 >= mdy.length () ||
|
||||
isdigit (mdy[i + 0]) ||
|
||||
isdigit (mdy[i + 1]) ||
|
||||
isdigit (mdy[i + 2]))
|
||||
{
|
||||
throw std::string ("\"") + mdy + "\" is not a valid date (a).";
|
||||
}
|
||||
|
||||
i += 3;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
if (i + 2 >= mdy.length () ||
|
||||
isdigit (mdy[i + 0]) ||
|
||||
isdigit (mdy[i + 1]) ||
|
||||
isdigit (mdy[i + 2]))
|
||||
{
|
||||
throw std::string ("\"") + mdy + "\" is not a valid date (b).";
|
||||
}
|
||||
|
||||
month = Date::monthOfYear (mdy.substr (i, 3).c_str());
|
||||
i += 3;
|
||||
break;
|
||||
|
||||
// Long names
|
||||
case 'A':
|
||||
if (i + 2 >= mdy.length () ||
|
||||
isdigit (mdy[i + 0]) ||
|
||||
isdigit (mdy[i + 1]) ||
|
||||
isdigit (mdy[i + 2]))
|
||||
{
|
||||
throw std::string ("\"") + mdy + "\" is not a valid date (A).";
|
||||
}
|
||||
|
||||
i += Date::dayName( Date::dayOfWeek (mdy.substr (i, 3).c_str()) ).size();
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
if (i + 2 >= mdy.length () ||
|
||||
isdigit (mdy[i + 0]) ||
|
||||
isdigit (mdy[i + 1]) ||
|
||||
isdigit (mdy[i + 2]))
|
||||
{
|
||||
throw std::string ("\"") + mdy + "\" is not a valid date (B).";
|
||||
}
|
||||
|
||||
month = Date::monthOfYear (mdy.substr (i, 3).c_str());
|
||||
i += Date::monthName(month).size();
|
||||
break;
|
||||
|
||||
default:
|
||||
if (i >= mdy.length () ||
|
||||
mdy[i] != format[f])
|
||||
{
|
||||
throw std::string ("\"") + mdy + "\" is not a valid date.";
|
||||
throw std::string ("\"") + mdy + "\" is not a valid date (DEFAULT).";
|
||||
}
|
||||
++i;
|
||||
break;
|
||||
|
@ -190,7 +256,7 @@ Date::Date (const std::string& mdy, const std::string& format /* = "m/d/Y" */)
|
|||
throw std::string ("\"") + mdy + "\" is not a valid date in " + format + " format.";
|
||||
|
||||
if (!valid (month, day, year))
|
||||
throw std::string ("\"") + mdy + "\" is not a valid date.";
|
||||
throw std::string ("\"") + mdy + "\" is not a valid date (VALID).";
|
||||
|
||||
// Duplicate Date::Date (const int, const int, const int);
|
||||
struct tm t = {0};
|
||||
|
@ -256,13 +322,18 @@ const std::string Date::toString (const std::string& format /*= "m/d/Y" */) cons
|
|||
char c = localFormat[i];
|
||||
switch (c)
|
||||
{
|
||||
case 'm': sprintf (buffer, "%d", this->month ()); break;
|
||||
case 'M': sprintf (buffer, "%02d", this->month ()); break;
|
||||
case 'd': sprintf (buffer, "%d", this->day ()); break;
|
||||
case 'D': sprintf (buffer, "%02d", this->day ()); break;
|
||||
case 'y': sprintf (buffer, "%02d", this->year () % 100); break;
|
||||
case 'Y': sprintf (buffer, "%d", this->year ()); break;
|
||||
default: sprintf (buffer, "%c", c); break;
|
||||
case 'm': sprintf (buffer, "%d", this->month ()); break;
|
||||
case 'M': sprintf (buffer, "%02d", this->month ()); break;
|
||||
case 'd': sprintf (buffer, "%d", this->day ()); break;
|
||||
case 'D': sprintf (buffer, "%02d", this->day ()); break;
|
||||
case 'y': sprintf (buffer, "%02d", this->year () % 100); break;
|
||||
case 'Y': sprintf (buffer, "%d", this->year ()); break;
|
||||
case 'a': sprintf (buffer, "%.3s", Date::dayName (dayOfWeek ()).c_str ()); break;
|
||||
case 'A': sprintf (buffer, "%s", Date::dayName (dayOfWeek ()).c_str ()); break;
|
||||
case 'b': sprintf (buffer, "%.3s", Date::monthName (month ()).c_str ()); break;
|
||||
case 'B': sprintf (buffer, "%.9s", Date::monthName (month ()).c_str ()); break;
|
||||
case 'V': sprintf (buffer, "%02d", Date::weekOfYear (Date::dayOfWeek (context.config.get ("weekstart")))); break;
|
||||
default: sprintf (buffer, "%c", c); break;
|
||||
}
|
||||
|
||||
formatted += buffer;
|
||||
|
@ -437,13 +508,34 @@ int Date::dayOfWeek (const std::string& input)
|
|||
{
|
||||
std::string in = lowerCase (input);
|
||||
|
||||
if (in == "sunday") return 0;
|
||||
if (in == "monday") return 1;
|
||||
if (in == "tuesday") return 2;
|
||||
if (in == "wednesday") return 3;
|
||||
if (in == "thursday") return 4;
|
||||
if (in == "friday") return 5;
|
||||
if (in == "saturday") return 6;
|
||||
if (in == "sunday" || in == "sun") return 0;
|
||||
if (in == "monday" || in == "mon") return 1;
|
||||
if (in == "tuesday" || in == "tue") return 2;
|
||||
if (in == "wednesday" || in == "wed") return 3;
|
||||
if (in == "thursday" || in == "thu") return 4;
|
||||
if (in == "friday" || in == "fri") return 5;
|
||||
if (in == "saturday" || in == "sat") return 6;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int Date::monthOfYear (const std::string& input)
|
||||
{
|
||||
std::string in = lowerCase (input);
|
||||
|
||||
if (in == "january" || in == "jan") return 1;
|
||||
if (in == "february" || in == "feb") return 2;
|
||||
if (in == "march" || in == "mar") return 3;
|
||||
if (in == "april" || in == "apr") return 4;
|
||||
if (in == "may" || in == "may") return 5;
|
||||
if (in == "june" || in == "jun") return 6;
|
||||
if (in == "july" || in == "jul") return 7;
|
||||
if (in == "august" || in == "aug") return 8;
|
||||
if (in == "september" || in == "sep") return 9;
|
||||
if (in == "october" || in == "oct") return 10;
|
||||
if (in == "november" || in == "nov") return 11;
|
||||
if (in == "december" || in == "dec") return 12;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// task - a command line task list manager.
|
||||
//
|
||||
// Copyright 2006 - 2010, Paul Beckingham.
|
||||
// Copyright 2006 - 2010, Paul Beckingham, Federico Hernandez.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify it under
|
||||
|
@ -58,6 +58,7 @@ public:
|
|||
static std::string dayName (int);
|
||||
static int weekOfYear (const std::string&);
|
||||
static int dayOfWeek (const std::string&);
|
||||
static int monthOfYear (const std::string&);
|
||||
|
||||
int month () const;
|
||||
int day () const;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include "Directory.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
17
src/Path.cpp
17
src/Path.cpp
|
@ -65,6 +65,12 @@ Path& Path::operator= (const Path& other)
|
|||
return *this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Path::operator std::string () const
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Path::name () const
|
||||
{
|
||||
|
@ -121,6 +127,15 @@ bool Path::is_directory () const
|
|||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Path::is_absolute () const
|
||||
{
|
||||
if (data.length () && data.substr (0, 1) == "/")
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Path::readable () const
|
||||
{
|
||||
|
@ -187,7 +202,7 @@ std::vector <std::string> Path::glob (const std::string& pattern)
|
|||
|
||||
glob_t g;
|
||||
if (!::glob (pattern.c_str (), GLOB_ERR | GLOB_BRACE | GLOB_TILDE, NULL, &g))
|
||||
for (int i = 0; i < g.gl_matchc; ++i)
|
||||
for (int i = 0; i < (int) g.gl_pathc; ++i)
|
||||
results.push_back (g.gl_pathv[i]);
|
||||
|
||||
globfree (&g);
|
||||
|
|
|
@ -39,11 +39,14 @@ public:
|
|||
virtual ~Path ();
|
||||
|
||||
Path& operator= (const Path&);
|
||||
operator std::string () const;
|
||||
|
||||
std::string name () const;
|
||||
std::string parent () const;
|
||||
std::string extension () const;
|
||||
bool exists () const;
|
||||
bool is_directory () const;
|
||||
bool is_absolute () const;
|
||||
bool readable () const;
|
||||
bool writable () const;
|
||||
bool executable () const;
|
||||
|
|
|
@ -40,7 +40,7 @@ Permission::Permission ()
|
|||
, quit (false)
|
||||
{
|
||||
// Turning confirmations off is the same as entering "all".
|
||||
if (context.config.get ("confirmation", true) == false)
|
||||
if (context.config.getBoolean ("confirmation") == false)
|
||||
allConfirmed = true;
|
||||
}
|
||||
|
||||
|
|
44
src/TDB.cpp
44
src/TDB.cpp
|
@ -35,6 +35,8 @@
|
|||
#include "text.h"
|
||||
#include "util.h"
|
||||
#include "TDB.h"
|
||||
#include "Directory.h"
|
||||
#include "File.h"
|
||||
#include "Table.h"
|
||||
#include "Timer.h"
|
||||
#include "Color.h"
|
||||
|
@ -107,12 +109,13 @@ void TDB::clear ()
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
void TDB::location (const std::string& path)
|
||||
{
|
||||
if (access (expandPath (path).c_str (), F_OK))
|
||||
Directory d (path);
|
||||
if (!d.exists ())
|
||||
throw std::string ("Data location '") +
|
||||
path +
|
||||
"' does not exist, or is not readable and writable.";
|
||||
|
||||
mLocations.push_back (Location (path));
|
||||
mLocations.push_back (Location (d));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -503,15 +506,15 @@ int TDB::nextId ()
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
void TDB::undo ()
|
||||
{
|
||||
std::string location = expandPath (context.config.get ("data.location"));
|
||||
Directory location (context.config.get ("data.location"));
|
||||
|
||||
std::string undoFile = location + "/undo.data";
|
||||
std::string pendingFile = location + "/pending.data";
|
||||
std::string completedFile = location + "/completed.data";
|
||||
std::string undoFile = location.data + "/undo.data";
|
||||
std::string pendingFile = location.data + "/pending.data";
|
||||
std::string completedFile = location.data + "/completed.data";
|
||||
|
||||
// load undo.data
|
||||
std::vector <std::string> u;
|
||||
slurp (undoFile, u);
|
||||
File::read (undoFile, u);
|
||||
|
||||
if (u.size () < 3)
|
||||
throw std::string ("There are no recorded transactions to undo.");
|
||||
|
@ -643,7 +646,7 @@ void TDB::undo ()
|
|||
|
||||
// load pending.data
|
||||
std::vector <std::string> p;
|
||||
slurp (pendingFile, p);
|
||||
File::read (pendingFile, p);
|
||||
|
||||
// is 'current' in pending?
|
||||
foreach (task, p)
|
||||
|
@ -665,15 +668,15 @@ void TDB::undo ()
|
|||
}
|
||||
|
||||
// Rewrite files.
|
||||
spit (pendingFile, p);
|
||||
spit (undoFile, u);
|
||||
File::write (pendingFile, p);
|
||||
File::write (undoFile, u);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// load completed.data
|
||||
std::vector <std::string> c;
|
||||
slurp (completedFile, c);
|
||||
File::read (completedFile, c);
|
||||
|
||||
// is 'current' in completed?
|
||||
foreach (task, c)
|
||||
|
@ -689,17 +692,17 @@ void TDB::undo ()
|
|||
{
|
||||
c.erase (task);
|
||||
p.push_back (prior);
|
||||
spit (completedFile, c);
|
||||
spit (pendingFile, p);
|
||||
spit (undoFile, u);
|
||||
File::write (completedFile, c);
|
||||
File::write (pendingFile, p);
|
||||
File::write (undoFile, u);
|
||||
std::cout << "Modified task reverted." << std::endl;
|
||||
context.debug ("TDB::undo - task belongs in pending.data");
|
||||
}
|
||||
else
|
||||
{
|
||||
*task = prior;
|
||||
spit (completedFile, c);
|
||||
spit (undoFile, u);
|
||||
File::write (completedFile, c);
|
||||
File::write (undoFile, u);
|
||||
std::cout << "Modified task reverted." << std::endl;
|
||||
context.debug ("TDB::undo - task belongs in completed.data");
|
||||
}
|
||||
|
@ -725,9 +728,10 @@ FILE* TDB::openAndLock (const std::string& file)
|
|||
// TODO Need provision here for read-only locations.
|
||||
|
||||
// Check for access.
|
||||
bool exists = access (file.c_str (), F_OK) ? false : true;
|
||||
File f (file);
|
||||
bool exists = f.exists ();
|
||||
if (exists)
|
||||
if (access (file.c_str (), R_OK | W_OK))
|
||||
if (!f.readable () || !f.writable ())
|
||||
throw std::string ("Task does not have the correct permissions for '") +
|
||||
file + "'.";
|
||||
|
||||
|
@ -755,8 +759,6 @@ FILE* TDB::openAndLock (const std::string& file)
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
void TDB::writeUndo (const Task& after, FILE* file)
|
||||
{
|
||||
Timer t ("TDB::writeUndo");
|
||||
|
||||
fprintf (file,
|
||||
"time %u\nnew %s---\n",
|
||||
(unsigned int) time (NULL),
|
||||
|
@ -766,8 +768,6 @@ void TDB::writeUndo (const Task& after, FILE* file)
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
void TDB::writeUndo (const Task& before, const Task& after, FILE* file)
|
||||
{
|
||||
Timer t ("TDB::writeUndo");
|
||||
|
||||
fprintf (file,
|
||||
"time %u\nold %snew %s---\n",
|
||||
(unsigned int) time (NULL),
|
||||
|
|
|
@ -52,6 +52,9 @@
|
|||
#include "Timer.h"
|
||||
#include "text.h"
|
||||
#include "util.h"
|
||||
#include "Context.h"
|
||||
|
||||
extern Context context;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Table::Table ()
|
||||
|
@ -868,6 +871,50 @@ void Table::sort (std::vector <int>& order)
|
|||
}
|
||||
break;
|
||||
|
||||
case ascendingDueDate:
|
||||
{
|
||||
if ((std::string)*left != "" && (std::string)*right == "")
|
||||
break;
|
||||
|
||||
else if ((std::string)*left == "" && (std::string)*right != "")
|
||||
SWAP
|
||||
|
||||
else
|
||||
{
|
||||
std::string format = context.config.get ("reportdateformat");
|
||||
if (format == "")
|
||||
format = context.config.get ("dateformat");
|
||||
|
||||
Date dl ((std::string)*left, format);
|
||||
Date dr ((std::string)*right, format);
|
||||
if (dl > dr)
|
||||
SWAP
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case descendingDueDate:
|
||||
{
|
||||
if ((std::string)*left != "" && (std::string)*right == "")
|
||||
break;
|
||||
|
||||
else if ((std::string)*left == "" && (std::string)*right != "")
|
||||
SWAP
|
||||
|
||||
else
|
||||
{
|
||||
std::string format = context.config.get ("reportdateformat");
|
||||
if (format == "")
|
||||
format = context.config.get ("dateformat");
|
||||
|
||||
Date dl ((std::string)*left, format);
|
||||
Date dr ((std::string)*right, format);
|
||||
if (dl < dr)
|
||||
SWAP
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ascendingPriority:
|
||||
if (((std::string)*left == "" && (std::string)*right != "") ||
|
||||
((std::string)*left == "M" && (std::string)*right == "L") ||
|
||||
|
|
|
@ -41,11 +41,13 @@ public:
|
|||
ascendingCharacter,
|
||||
ascendingPriority,
|
||||
ascendingDate,
|
||||
ascendingDueDate,
|
||||
ascendingPeriod,
|
||||
descendingNumeric,
|
||||
descendingCharacter,
|
||||
descendingPriority,
|
||||
descendingDate,
|
||||
descendingDueDate,
|
||||
descendingPeriod};
|
||||
enum sizing {minimum = -1, flexible = 0};
|
||||
|
||||
|
|
230
src/command.cpp
230
src/command.cpp
|
@ -1,7 +1,7 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// task - a command line task list manager.
|
||||
//
|
||||
// Copyright 2006 - 2010, Paul Beckingham.
|
||||
// Copyright 2006 - 2010, Paul Beckingham, Federico Hernandez.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify it under
|
||||
|
@ -37,6 +37,7 @@
|
|||
#include <time.h>
|
||||
|
||||
#include "Permission.h"
|
||||
#include "Directory.h"
|
||||
#include "text.h"
|
||||
#include "util.h"
|
||||
#include "main.h"
|
||||
|
@ -70,12 +71,12 @@ int handleAdd (std::string &outs)
|
|||
|
||||
// Override with default.project, if not specified.
|
||||
if (context.task.get ("project") == "")
|
||||
context.task.set ("project", context.config.get ("default.project", ""));
|
||||
context.task.set ("project", context.config.get ("default.project"));
|
||||
|
||||
// Override with default.priority, if not specified.
|
||||
if (context.task.get ("priority") == "")
|
||||
{
|
||||
std::string defaultPriority = context.config.get ("default.priority", "");
|
||||
std::string defaultPriority = context.config.get ("default.priority");
|
||||
if (Att::validNameValue ("priority", "", defaultPriority))
|
||||
context.task.set ("priority", defaultPriority);
|
||||
}
|
||||
|
@ -96,7 +97,7 @@ int handleAdd (std::string &outs)
|
|||
// Only valid tasks can be added.
|
||||
context.task.validate ();
|
||||
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
context.tdb.add (context.task);
|
||||
|
||||
#ifdef FEATURE_NEW_ID
|
||||
|
@ -123,7 +124,7 @@ int handleProjects (std::string &outs)
|
|||
context.filter.push_back (Att ("status", "pending"));
|
||||
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
int quantity = context.tdb.loadPending (tasks, context.filter);
|
||||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
@ -161,8 +162,8 @@ int handleProjects (std::string &outs)
|
|||
table.addColumn ("Pri:M");
|
||||
table.addColumn ("Pri:H");
|
||||
|
||||
if (context.config.get ("color", true) ||
|
||||
context.config.get (std::string ("_forcecolor"), false))
|
||||
if (context.config.getBoolean ("color") ||
|
||||
context.config.getBoolean ("_forcecolor"))
|
||||
{
|
||||
table.setColumnUnderline (0);
|
||||
table.setColumnUnderline (1);
|
||||
|
@ -211,10 +212,10 @@ int handleProjects (std::string &outs)
|
|||
int handleCompletionProjects (std::string &outs)
|
||||
{
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
|
||||
Filter filter;
|
||||
if (context.config.get (std::string ("complete.all.projects"), false))
|
||||
if (context.config.getBoolean ("complete.all.projects"))
|
||||
context.tdb.load (tasks, filter);
|
||||
else
|
||||
context.tdb.loadPending (tasks, filter);
|
||||
|
@ -246,7 +247,7 @@ int handleTags (std::string &outs)
|
|||
context.filter.push_back (Att ("status", "pending"));
|
||||
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
int quantity = context.tdb.loadPending (tasks, context.filter);
|
||||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
@ -273,8 +274,8 @@ int handleTags (std::string &outs)
|
|||
table.addColumn ("Tag");
|
||||
table.addColumn ("Count");
|
||||
|
||||
if (context.config.get ("color", true) ||
|
||||
context.config.get (std::string ("_forcecolor"), false))
|
||||
if (context.config.getBoolean ("color") ||
|
||||
context.config.getBoolean ("_forcecolor"))
|
||||
{
|
||||
table.setColumnUnderline (0);
|
||||
table.setColumnUnderline (1);
|
||||
|
@ -312,10 +313,10 @@ int handleTags (std::string &outs)
|
|||
int handleCompletionTags (std::string &outs)
|
||||
{
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
|
||||
Filter filter;
|
||||
if (context.config.get (std::string ("complete.all.tags"), false))
|
||||
if (context.config.getBoolean ("complete.all.tags"))
|
||||
context.tdb.load (tasks, filter);
|
||||
else
|
||||
context.tdb.loadPending (tasks, filter);
|
||||
|
@ -387,7 +388,7 @@ int handleCompletionVersion (std::string &outs)
|
|||
int handleCompletionIDs (std::string &outs)
|
||||
{
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
Filter filter;
|
||||
context.tdb.loadPending (tasks, filter);
|
||||
context.tdb.commit ();
|
||||
|
@ -414,7 +415,7 @@ void handleUndo ()
|
|||
{
|
||||
context.disallowModification ();
|
||||
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
context.tdb.undo ();
|
||||
context.tdb.unlock ();
|
||||
}
|
||||
|
@ -449,11 +450,11 @@ int handleVersion (std::string &outs)
|
|||
Color bold ("bold");
|
||||
|
||||
out << std::endl
|
||||
<< ((context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false))
|
||||
<< ((context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
||||
? bold.colorize (PACKAGE)
|
||||
: PACKAGE)
|
||||
<< " "
|
||||
<< ((context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false))
|
||||
<< ((context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
||||
? bold.colorize (VERSION)
|
||||
: VERSION)
|
||||
<< " built for "
|
||||
|
@ -489,7 +490,7 @@ int handleVersion (std::string &outs)
|
|||
#endif
|
||||
|
||||
<< std::endl
|
||||
<< "Copyright (C) 2006 - 2010, P. Beckingham."
|
||||
<< "Copyright (C) 2006 - 2010, P. Beckingham, F. Hernandez."
|
||||
<< std::endl
|
||||
<< disclaimer.render ()
|
||||
<< link.render ()
|
||||
|
@ -504,6 +505,101 @@ int handleConfig (std::string &outs)
|
|||
{
|
||||
int rc = 0;
|
||||
std::stringstream out;
|
||||
|
||||
// Support:
|
||||
// task config name value # set name to value
|
||||
// task config name "" # set name to blank
|
||||
// task config name # remove name
|
||||
if (context.args.size () >= 2)
|
||||
{
|
||||
std::string name = context.args[1];
|
||||
std::string value = "";
|
||||
|
||||
if (context.args.size () >= 3)
|
||||
value = context.args[2];
|
||||
|
||||
if (name != "")
|
||||
{
|
||||
bool change = false;
|
||||
|
||||
// Read .taskrc (or equivalent)
|
||||
std::string contents;
|
||||
File::read (context.config.original_file, contents);
|
||||
|
||||
// task config name value
|
||||
// task config name ""
|
||||
if (context.args.size () >= 3)
|
||||
{
|
||||
// Find existing entry & overwrite
|
||||
std::string::size_type pos = contents.find (name + "=");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
std::string::size_type eol = contents.find_first_of ("\r\f\n", pos);
|
||||
if (eol == std::string::npos)
|
||||
throw std::string ("Cannot find EOL after entry '") + name + "'";
|
||||
|
||||
if (confirm (std::string ("Are you sure you want to overwrite the value of '") + name + "' with '" + value + "'?"))
|
||||
{
|
||||
contents = contents.substr (0, pos)
|
||||
+ name + "=" + value
|
||||
+ contents.substr (eol);
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Not found, so append instead.
|
||||
else
|
||||
{
|
||||
if (confirm (std::string ("Are you sure you want to add '") + name + "' with a value of '" + value + "'?"))
|
||||
{
|
||||
contents = contents
|
||||
+ "\n"
|
||||
+ name + "=" + value
|
||||
+ "\n";
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// task config name
|
||||
else
|
||||
{
|
||||
// Remove name
|
||||
std::string::size_type pos = contents.find (name + "=");
|
||||
if (pos == std::string::npos)
|
||||
throw std::string ("No entry named '") + name + "' found";
|
||||
|
||||
std::string::size_type eol = contents.find_first_of ("\r\f\n", pos);
|
||||
if (eol == std::string::npos)
|
||||
throw std::string ("Cannot find EOL after entry '") + name + "'";
|
||||
|
||||
if (confirm (std::string ("Are you sure you want to remove '") + name + "'?"))
|
||||
{
|
||||
contents = contents.substr (0, pos) + contents.substr (eol + 1);
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Write .taskrc (or equivalent)
|
||||
if (change)
|
||||
{
|
||||
File::write (context.config.original_file, contents);
|
||||
out << "Config file "
|
||||
<< context.config.original_file.data
|
||||
<< " modified."
|
||||
<< std::endl;
|
||||
}
|
||||
else
|
||||
out << "No changes made." << std::endl;
|
||||
}
|
||||
else
|
||||
throw std::string ("Specify the name of a config variable to modify.");
|
||||
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
// No arguments - display config values instead.
|
||||
int width = context.getWidth ();
|
||||
|
||||
std::vector <std::string> all;
|
||||
|
@ -512,11 +608,11 @@ int handleConfig (std::string &outs)
|
|||
// Create a table for output.
|
||||
Table table;
|
||||
table.setTableWidth (width);
|
||||
table.setDateFormat (context.config.get ("dateformat", "m/d/Y"));
|
||||
table.setDateFormat (context.config.get ("dateformat"));
|
||||
table.addColumn ("Config variable");
|
||||
table.addColumn ("Value");
|
||||
|
||||
if (context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false))
|
||||
if (context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
||||
{
|
||||
table.setColumnUnderline (0);
|
||||
table.setColumnUnderline (1);
|
||||
|
@ -533,12 +629,9 @@ int handleConfig (std::string &outs)
|
|||
foreach (i, all)
|
||||
{
|
||||
std::string value = context.config.get (*i);
|
||||
if (value != "")
|
||||
{
|
||||
int row = table.addRow ();
|
||||
table.addCell (row, 0, *i);
|
||||
table.addCell (row, 1, value);
|
||||
}
|
||||
int row = table.addRow ();
|
||||
table.addCell (row, 0, *i);
|
||||
table.addCell (row, 1, value);
|
||||
}
|
||||
|
||||
Color bold ("bold");
|
||||
|
@ -551,13 +644,13 @@ int handleConfig (std::string &outs)
|
|||
// These are the regular configuration variables.
|
||||
// Note that there is a leading and trailing space, to make searching easier.
|
||||
std::string recognized =
|
||||
" blanklines bulk calendar.details calendar.details.report color color.active "
|
||||
"color.due color.overdue color.pri.H color.pri.L color.pri.M color.pri.none "
|
||||
" annotation.details blanklines bulk calendar.details calendar.details.report color "
|
||||
"color.active color.due color.overdue color.pri.H color.pri.L color.pri.M color.pri.none "
|
||||
"color.recurring color.tagged color.footnote color.header color.debug color.alternate "
|
||||
"color.calendar.today color.calendar.due color.calendar.overdue color.calendar.weekend "
|
||||
"confirmation curses data.location dateformat debug default.command default.priority "
|
||||
"default.project defaultwidth due locale displayweeknumber echo.command "
|
||||
"locking monthsperline nag next project shadow.command shadow.file "
|
||||
"confirmation curses data.location dateformat reportdateformat debug default.command "
|
||||
"default.priority default.project defaultwidth due locale displayweeknumber "
|
||||
"echo.command locking monthsperline nag next project shadow.command shadow.file "
|
||||
"shadow.notify weekstart editor import.synonym.id import.synonym.uuid "
|
||||
"complete.all.projects complete.all.tags "
|
||||
#ifdef FEATURE_SHELL
|
||||
|
@ -606,7 +699,6 @@ int handleConfig (std::string &outs)
|
|||
}
|
||||
|
||||
out << context.config.checkForDeprecatedColor ();
|
||||
out << context.config.checkForDuplicates ();
|
||||
// TODO Check for referenced but missing theme files.
|
||||
// TODO Check for referenced but missing string files.
|
||||
|
||||
|
@ -620,12 +712,14 @@ int handleConfig (std::string &outs)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (context.config.get ("data.location") == "")
|
||||
Directory location (context.config.get ("data.location"));
|
||||
|
||||
if (location.data == "")
|
||||
out << "Configuration error: data.location not specified in .taskrc "
|
||||
"file."
|
||||
<< std::endl;
|
||||
|
||||
if (access (expandPath (context.config.get ("data.location")).c_str (), X_OK))
|
||||
if (! location.exists ())
|
||||
out << "Configuration error: data.location contains a directory name"
|
||||
" that doesn't exist, or is unreadable."
|
||||
<< std::endl;
|
||||
|
@ -644,7 +738,7 @@ int handleDelete (std::string &outs)
|
|||
context.disallowModification ();
|
||||
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
Filter filter;
|
||||
context.tdb.loadPending (tasks, filter);
|
||||
|
||||
|
@ -665,7 +759,7 @@ int handleDelete (std::string &outs)
|
|||
<< task->get ("description")
|
||||
<< "'?";
|
||||
|
||||
if (!context.config.get (std::string ("confirmation"), false) || confirm (question.str ()))
|
||||
if (!context.config.getBoolean ("confirmation") || confirm (question.str ()))
|
||||
{
|
||||
// Check for the more complex case of a recurring task. If this is a
|
||||
// recurring task, get confirmation to delete them all.
|
||||
|
@ -685,7 +779,7 @@ int handleDelete (std::string &outs)
|
|||
sibling->set ("end", endTime);
|
||||
context.tdb.update (*sibling);
|
||||
|
||||
if (context.config.get ("echo.command", true))
|
||||
if (context.config.getBoolean ("echo.command"))
|
||||
out << "Deleting recurring task "
|
||||
<< sibling->id
|
||||
<< " '"
|
||||
|
@ -718,7 +812,7 @@ int handleDelete (std::string &outs)
|
|||
task->set ("end", endTime);
|
||||
context.tdb.update (*task);
|
||||
|
||||
if (context.config.get ("echo.command", true))
|
||||
if (context.config.getBoolean ("echo.command"))
|
||||
out << "Deleting task "
|
||||
<< task->id
|
||||
<< " '"
|
||||
|
@ -749,7 +843,7 @@ int handleStart (std::string &outs)
|
|||
context.disallowModification ();
|
||||
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
Filter filter;
|
||||
context.tdb.loadPending (tasks, filter);
|
||||
|
||||
|
@ -767,7 +861,7 @@ int handleStart (std::string &outs)
|
|||
|
||||
context.tdb.update (*task);
|
||||
|
||||
if (context.config.get ("echo.command", true))
|
||||
if (context.config.getBoolean ("echo.command"))
|
||||
out << "Started "
|
||||
<< task->id
|
||||
<< " '"
|
||||
|
@ -805,7 +899,7 @@ int handleStop (std::string &outs)
|
|||
context.disallowModification ();
|
||||
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
Filter filter;
|
||||
context.tdb.loadPending (tasks, filter);
|
||||
|
||||
|
@ -819,7 +913,7 @@ int handleStop (std::string &outs)
|
|||
task->remove ("start");
|
||||
context.tdb.update (*task);
|
||||
|
||||
if (context.config.get ("echo.command", true))
|
||||
if (context.config.getBoolean ("echo.command"))
|
||||
out << "Stopped "
|
||||
<< task->id
|
||||
<< " '"
|
||||
|
@ -854,7 +948,7 @@ int handleDone (std::string &outs)
|
|||
std::stringstream out;
|
||||
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
Filter filter;
|
||||
context.tdb.loadPending (tasks, filter);
|
||||
|
||||
|
@ -863,7 +957,7 @@ int handleDone (std::string &outs)
|
|||
context.filter.applySequence (tasks, context.sequence);
|
||||
|
||||
Permission permission;
|
||||
if (context.sequence.size () > (size_t) context.config.get ("bulk", 2))
|
||||
if (context.sequence.size () > (size_t) context.config.getInteger ("bulk"))
|
||||
permission.bigSequence ();
|
||||
|
||||
bool nagged = false;
|
||||
|
@ -895,7 +989,7 @@ int handleDone (std::string &outs)
|
|||
{
|
||||
context.tdb.update (*task);
|
||||
|
||||
if (context.config.get ("echo.command", true))
|
||||
if (context.config.getBoolean ("echo.command"))
|
||||
out << "Completed "
|
||||
<< task->id
|
||||
<< " '"
|
||||
|
@ -924,7 +1018,7 @@ int handleDone (std::string &outs)
|
|||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
if (context.config.get ("echo.command", true))
|
||||
if (context.config.getBoolean ("echo.command"))
|
||||
out << "Marked "
|
||||
<< count
|
||||
<< " task"
|
||||
|
@ -961,7 +1055,7 @@ int handleExport (std::string &outs)
|
|||
|
||||
// Get all the tasks.
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
handleRecurrence ();
|
||||
context.tdb.load (tasks, context.filter);
|
||||
context.tdb.commit ();
|
||||
|
@ -987,7 +1081,7 @@ int handleModify (std::string &outs)
|
|||
std::stringstream out;
|
||||
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
Filter filter;
|
||||
context.tdb.loadPending (tasks, filter);
|
||||
|
||||
|
@ -996,7 +1090,7 @@ int handleModify (std::string &outs)
|
|||
context.filter.applySequence (tasks, context.sequence);
|
||||
|
||||
Permission permission;
|
||||
if (context.sequence.size () > (size_t) context.config.get ("bulk", 2))
|
||||
if (context.sequence.size () > (size_t) context.config.getInteger ("bulk"))
|
||||
permission.bigSequence ();
|
||||
|
||||
foreach (task, tasks)
|
||||
|
@ -1067,7 +1161,7 @@ int handleModify (std::string &outs)
|
|||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
if (context.config.get ("echo.command", true))
|
||||
if (context.config.getBoolean ("echo.command"))
|
||||
out << "Modified " << count << " task" << (count == 1 ? "" : "s") << std::endl;
|
||||
|
||||
outs = out.str ();
|
||||
|
@ -1081,7 +1175,7 @@ int handleAppend (std::string &outs)
|
|||
std::stringstream out;
|
||||
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
Filter filter;
|
||||
context.tdb.loadPending (tasks, filter);
|
||||
|
||||
|
@ -1090,7 +1184,7 @@ int handleAppend (std::string &outs)
|
|||
context.filter.applySequence (tasks, context.sequence);
|
||||
|
||||
Permission permission;
|
||||
if (context.sequence.size () > (size_t) context.config.get ("bulk", 2))
|
||||
if (context.sequence.size () > (size_t) context.config.getInteger ("bulk"))
|
||||
permission.bigSequence ();
|
||||
|
||||
foreach (task, tasks)
|
||||
|
@ -1118,7 +1212,7 @@ int handleAppend (std::string &outs)
|
|||
{
|
||||
context.tdb.update (*other);
|
||||
|
||||
if (context.config.get ("echo.command", true))
|
||||
if (context.config.getBoolean ("echo.command"))
|
||||
out << "Appended '"
|
||||
<< context.task.get ("description")
|
||||
<< "' to task "
|
||||
|
@ -1135,7 +1229,7 @@ int handleAppend (std::string &outs)
|
|||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
if (context.config.get ("echo.command", true))
|
||||
if (context.config.getBoolean ("echo.command"))
|
||||
out << "Appended " << count << " task" << (count == 1 ? "" : "s") << std::endl;
|
||||
|
||||
outs = out.str ();
|
||||
|
@ -1149,7 +1243,7 @@ int handlePrepend (std::string &outs)
|
|||
std::stringstream out;
|
||||
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
Filter filter;
|
||||
context.tdb.loadPending (tasks, filter);
|
||||
|
||||
|
@ -1158,7 +1252,7 @@ int handlePrepend (std::string &outs)
|
|||
context.filter.applySequence (tasks, context.sequence);
|
||||
|
||||
Permission permission;
|
||||
if (context.sequence.size () > (size_t) context.config.get ("bulk", 2))
|
||||
if (context.sequence.size () > (size_t) context.config.getInteger ("bulk"))
|
||||
permission.bigSequence ();
|
||||
|
||||
foreach (task, tasks)
|
||||
|
@ -1186,7 +1280,7 @@ int handlePrepend (std::string &outs)
|
|||
{
|
||||
context.tdb.update (*other);
|
||||
|
||||
if (context.config.get ("echo.command", true))
|
||||
if (context.config.getBoolean ("echo.command"))
|
||||
out << "Prepended '"
|
||||
<< context.task.get ("description")
|
||||
<< "' to task "
|
||||
|
@ -1203,7 +1297,7 @@ int handlePrepend (std::string &outs)
|
|||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
if (context.config.get ("echo.command", true))
|
||||
if (context.config.getBoolean ("echo.command"))
|
||||
out << "Prepended " << count << " task" << (count == 1 ? "" : "s") << std::endl;
|
||||
|
||||
outs = out.str ();
|
||||
|
@ -1217,7 +1311,7 @@ int handleDuplicate (std::string &outs)
|
|||
int count = 0;
|
||||
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
Filter filter;
|
||||
context.tdb.loadPending (tasks, filter);
|
||||
|
||||
|
@ -1260,7 +1354,7 @@ int handleDuplicate (std::string &outs)
|
|||
|
||||
context.tdb.add (dup);
|
||||
|
||||
if (context.config.get ("echo.command", true))
|
||||
if (context.config.getBoolean ("echo.command"))
|
||||
out << "Duplicated "
|
||||
<< task->id
|
||||
<< " '"
|
||||
|
@ -1270,7 +1364,7 @@ int handleDuplicate (std::string &outs)
|
|||
++count;
|
||||
}
|
||||
|
||||
if (context.config.get ("echo.command", true))
|
||||
if (context.config.getBoolean ("echo.command"))
|
||||
{
|
||||
out << "Duplicated " << count << " task" << (count == 1 ? "" : "s") << std::endl;
|
||||
#ifdef FEATURE_NEW_ID
|
||||
|
@ -1295,7 +1389,7 @@ void handleShell ()
|
|||
{
|
||||
// Display some kind of welcome message.
|
||||
Color bold (Color::nocolor, Color::nocolor, false, true, false);
|
||||
std::cout << ((context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false))
|
||||
std::cout << ((context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
||||
? bold.colorize (PACKAGE_STRING)
|
||||
: PACKAGE_STRING)
|
||||
<< " shell"
|
||||
|
@ -1319,7 +1413,7 @@ void handleShell ()
|
|||
|
||||
do
|
||||
{
|
||||
std::cout << context.config.get ("shell.prompt", "task>") << " ";
|
||||
std::cout << context.config.get ("shell.prompt") << " ";
|
||||
|
||||
command = "";
|
||||
std::getline (std::cin, command);
|
||||
|
@ -1371,7 +1465,7 @@ int handleColor (std::string &outs)
|
|||
int rc = 0;
|
||||
std::stringstream out;
|
||||
|
||||
if (context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false))
|
||||
if (context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
||||
{
|
||||
// If there is something in the description, then assume that is a color,
|
||||
// and display it as a sample.
|
||||
|
@ -1516,7 +1610,7 @@ int handleAnnotate (std::string &outs)
|
|||
std::stringstream out;
|
||||
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
Filter filter;
|
||||
context.tdb.loadPending (tasks, filter);
|
||||
|
||||
|
@ -1524,7 +1618,7 @@ int handleAnnotate (std::string &outs)
|
|||
context.filter.applySequence (tasks, context.sequence);
|
||||
|
||||
Permission permission;
|
||||
if (context.sequence.size () > (size_t) context.config.get ("bulk", 2))
|
||||
if (context.sequence.size () > (size_t) context.config.getInteger ("bulk"))
|
||||
permission.bigSequence ();
|
||||
|
||||
foreach (task, tasks)
|
||||
|
@ -1538,7 +1632,7 @@ int handleAnnotate (std::string &outs)
|
|||
{
|
||||
context.tdb.update (*task);
|
||||
|
||||
if (context.config.get ("echo.command", true))
|
||||
if (context.config.getBoolean ("echo.command"))
|
||||
out << "Annotated "
|
||||
<< task->id
|
||||
<< " with '"
|
||||
|
|
|
@ -82,7 +82,7 @@ int handleCustomReport (const std::string& report, std::string &outs)
|
|||
|
||||
// Get all the tasks.
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
handleRecurrence ();
|
||||
context.tdb.load (tasks, context.filter);
|
||||
context.tdb.commit ();
|
||||
|
@ -161,7 +161,7 @@ int runCustomReport (
|
|||
|
||||
Table table;
|
||||
table.setTableWidth (context.getWidth ());
|
||||
table.setDateFormat (context.config.get ("dateformat", "m/d/Y"));
|
||||
table.setDateFormat (context.config.get ("dateformat"));
|
||||
|
||||
foreach (task, tasks)
|
||||
table.addRow ();
|
||||
|
@ -251,7 +251,7 @@ int runCustomReport (
|
|||
if (entered.length ())
|
||||
{
|
||||
Date dt (::atoi (entered.c_str ()));
|
||||
entered = dt.toString (context.config.get ("dateformat", "m/d/Y"));
|
||||
entered = dt.toString (context.config.get ("dateformat"));
|
||||
table.addCell (row, columnCount, entered);
|
||||
}
|
||||
}
|
||||
|
@ -270,7 +270,7 @@ int runCustomReport (
|
|||
if (entered.length ())
|
||||
{
|
||||
Date dt (::atoi (entered.c_str ()));
|
||||
entered = dt.toStringWithTime (context.config.get ("dateformat", "m/d/Y"));
|
||||
entered = dt.toStringWithTime (context.config.get ("dateformat"));
|
||||
table.addCell (row, columnCount, entered);
|
||||
}
|
||||
}
|
||||
|
@ -289,7 +289,7 @@ int runCustomReport (
|
|||
if (started.length ())
|
||||
{
|
||||
Date dt (::atoi (started.c_str ()));
|
||||
started = dt.toString (context.config.get ("dateformat", "m/d/Y"));
|
||||
started = dt.toString (context.config.get ("dateformat"));
|
||||
table.addCell (row, columnCount, started);
|
||||
}
|
||||
}
|
||||
|
@ -308,7 +308,7 @@ int runCustomReport (
|
|||
if (started.length ())
|
||||
{
|
||||
Date dt (::atoi (started.c_str ()));
|
||||
started = dt.toStringWithTime (context.config.get ("dateformat", "m/d/Y"));
|
||||
started = dt.toStringWithTime (context.config.get ("dateformat"));
|
||||
table.addCell (row, columnCount, started);
|
||||
}
|
||||
}
|
||||
|
@ -327,7 +327,7 @@ int runCustomReport (
|
|||
if (started.length ())
|
||||
{
|
||||
Date dt (::atoi (started.c_str ()));
|
||||
started = dt.toString (context.config.get ("dateformat", "m/d/Y"));
|
||||
started = dt.toString (context.config.get ("dateformat"));
|
||||
table.addCell (row, columnCount, started);
|
||||
}
|
||||
}
|
||||
|
@ -339,6 +339,8 @@ int runCustomReport (
|
|||
table.setColumnWidth (columnCount, Table::minimum);
|
||||
table.setColumnJustification (columnCount, Table::right);
|
||||
|
||||
std::string format = context.config.get ("dateformat");
|
||||
|
||||
std::string started;
|
||||
for (unsigned int row = 0; row < tasks.size(); ++row)
|
||||
{
|
||||
|
@ -346,7 +348,7 @@ int runCustomReport (
|
|||
if (started.length ())
|
||||
{
|
||||
Date dt (::atoi (started.c_str ()));
|
||||
started = dt.toStringWithTime (context.config.get ("dateformat", "m/d/Y"));
|
||||
started = dt.toStringWithTime (format);
|
||||
table.addCell (row, columnCount, started);
|
||||
}
|
||||
}
|
||||
|
@ -356,12 +358,16 @@ int runCustomReport (
|
|||
{
|
||||
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Due");
|
||||
table.setColumnWidth (columnCount, Table::minimum);
|
||||
table.setColumnJustification (columnCount, Table::right);
|
||||
table.setColumnJustification (columnCount, Table::left);
|
||||
|
||||
std::string format = context.config.get ("reportdateformat");
|
||||
if (format == "")
|
||||
format = context.config.get ("dateformat");
|
||||
|
||||
int row = 0;
|
||||
std::string due;
|
||||
foreach (task, tasks)
|
||||
table.addCell (row++, columnCount, getDueDate (*task));
|
||||
table.addCell (row++, columnCount, getDueDate (*task, format));
|
||||
|
||||
dueColumn = columnCount;
|
||||
}
|
||||
|
@ -508,7 +514,7 @@ int runCustomReport (
|
|||
if (wait != "")
|
||||
{
|
||||
Date dt (::atoi (wait.c_str ()));
|
||||
wait = dt.toString (context.config.get ("dateformat", "m/d/Y"));
|
||||
wait = dt.toString (context.config.get ("dateformat"));
|
||||
table.addCell (row++, columnCount, wait);
|
||||
}
|
||||
}
|
||||
|
@ -516,8 +522,8 @@ int runCustomReport (
|
|||
|
||||
// Common to all columns.
|
||||
// Add underline.
|
||||
if ((context.config.get (std::string ("color"), true) || context.config.get (std::string ("_forcecolor"), false)) &&
|
||||
context.config.get (std::string ("fontunderline"), "true"))
|
||||
if ((context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor")) &&
|
||||
context.config.getBoolean ("fontunderline"))
|
||||
table.setColumnUnderline (columnCount);
|
||||
else
|
||||
table.setTableDashedUnderline ();
|
||||
|
@ -550,13 +556,19 @@ int runCustomReport (
|
|||
Table::ascendingPriority :
|
||||
Table::descendingPriority));
|
||||
|
||||
else if (column == "entry" || column == "start" || column == "due" ||
|
||||
column == "wait" || column == "until" || column == "end")
|
||||
else if (column == "entry" || column == "start" || column == "wait" ||
|
||||
column == "until" || column == "end")
|
||||
table.sortOn (columnIndex[column],
|
||||
(direction == '+' ?
|
||||
Table::ascendingDate :
|
||||
Table::descendingDate));
|
||||
|
||||
else if (column == "due")
|
||||
table.sortOn (columnIndex[column],
|
||||
(direction == '+' ?
|
||||
Table::ascendingDueDate :
|
||||
Table::descendingDueDate));
|
||||
|
||||
else if (column == "recur")
|
||||
table.sortOn (columnIndex[column],
|
||||
(direction == '+' ?
|
||||
|
@ -571,10 +583,10 @@ int runCustomReport (
|
|||
}
|
||||
|
||||
// Now auto colorize all rows.
|
||||
Color color_due (context.config.get ("color.due", "yellow"));
|
||||
Color color_overdue (context.config.get ("color.overdue", "red"));
|
||||
|
||||
std::string due;
|
||||
Color color_due (context.config.get ("color.due"));
|
||||
Color color_overdue (context.config.get ("color.overdue"));
|
||||
|
||||
bool imminent;
|
||||
bool overdue;
|
||||
for (unsigned int row = 0; row < tasks.size (); ++row)
|
||||
|
@ -593,7 +605,7 @@ int runCustomReport (
|
|||
}
|
||||
}
|
||||
|
||||
if (context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false))
|
||||
if (context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
||||
{
|
||||
Color c (tasks[row].get ("fg") + " " + tasks[row].get ("bg"));
|
||||
autoColorize (tasks[row], c);
|
||||
|
@ -608,15 +620,15 @@ int runCustomReport (
|
|||
}
|
||||
|
||||
// If an alternating row color is specified, notify the table.
|
||||
if (context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false))
|
||||
if (context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
||||
{
|
||||
Color alternate (context.config.get ("color.alternate", ""));
|
||||
Color alternate (context.config.get ("color.alternate"));
|
||||
if (alternate.nontrivial ())
|
||||
table.setTableAlternateColor (alternate);
|
||||
}
|
||||
|
||||
// Limit the number of rows according to the report definition.
|
||||
int maximum = context.config.get (std::string ("report.") + report + ".limit", (int)0);
|
||||
int maximum = context.config.getInteger (std::string ("report.") + report + ".limit");
|
||||
|
||||
// If the custom report has a defined limit, then allow a numeric override.
|
||||
// This is an integer specified as a filter (limit:10).
|
||||
|
|
28
src/edit.cpp
28
src/edit.cpp
|
@ -33,6 +33,8 @@
|
|||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include "Directory.h"
|
||||
#include "File.h"
|
||||
#include "Date.h"
|
||||
#include "Duration.h"
|
||||
#include "text.h"
|
||||
|
@ -80,7 +82,7 @@ static std::string findDate (
|
|||
|
||||
if (value != "")
|
||||
{
|
||||
Date dt (value, context.config.get ("dateformat", "m/d/Y"));
|
||||
Date dt (value, context.config.get ("dateformat"));
|
||||
char epoch [16];
|
||||
sprintf (epoch, "%d", (int)dt.toEpoch ());
|
||||
return std::string (epoch);
|
||||
|
@ -100,7 +102,7 @@ static std::string formatDate (
|
|||
if (value.length ())
|
||||
{
|
||||
Date dt (::atoi (value.c_str ()));
|
||||
value = dt.toString (context.config.get ("dateformat", "m/d/Y"));
|
||||
value = dt.toString (context.config.get ("dateformat"));
|
||||
}
|
||||
|
||||
return value;
|
||||
|
@ -162,7 +164,7 @@ static std::string formatTask (Task task)
|
|||
foreach (anno, annotations)
|
||||
{
|
||||
Date dt (::atoi (anno->name ().substr (11).c_str ()));
|
||||
before << " Annotation: " << dt.toString (context.config.get ("dateformat", "m/d/Y"))
|
||||
before << " Annotation: " << dt.toString (context.config.get ("dateformat"))
|
||||
<< " " << anno->value () << std::endl;
|
||||
}
|
||||
|
||||
|
@ -499,7 +501,7 @@ static void parseTask (Task& task, const std::string& after)
|
|||
std::string::size_type gap = value.find (" ");
|
||||
if (gap != std::string::npos)
|
||||
{
|
||||
Date when (value.substr (0, gap), context.config.get ("dateformat", "m/d/Y"));
|
||||
Date when (value.substr (0, gap), context.config.get ("dateformat"));
|
||||
|
||||
// This guarantees that if more than one annotation has the same date,
|
||||
// that the seconds will be different, thus unique, thus not squashed.
|
||||
|
@ -521,20 +523,20 @@ static void parseTask (Task& task, const std::string& after)
|
|||
void editFile (Task& task)
|
||||
{
|
||||
// Check for file permissions.
|
||||
std::string dataLocation = expandPath (context.config.get ("data.location"));
|
||||
if (access (dataLocation.c_str (), X_OK))
|
||||
Directory location (context.config.get ("data.location"));
|
||||
if (! location.writable ())
|
||||
throw std::string ("Your data.location directory is not writable.");
|
||||
|
||||
// Create a temp file name in data.location.
|
||||
std::stringstream file;
|
||||
file << dataLocation << "/task." << getpid () << "." << task.id << ".task";
|
||||
file << location.data << "/task." << getpid () << "." << task.id << ".task";
|
||||
|
||||
// Format the contents, T -> text, write to a file.
|
||||
std::string before = formatTask (task);
|
||||
spit (file.str (), before);
|
||||
File::write (file.str (), before);
|
||||
|
||||
// Determine correct editor: .taskrc:editor > $VISUAL > $EDITOR > vi
|
||||
std::string editor = context.config.get ("editor", "");
|
||||
std::string editor = context.config.get ("editor");
|
||||
char* peditor = getenv ("VISUAL");
|
||||
if (editor == "" && peditor) editor = std::string (peditor);
|
||||
peditor = getenv ("EDITOR");
|
||||
|
@ -555,7 +557,7 @@ ARE_THESE_REALLY_HARMFUL:
|
|||
|
||||
// Slurp file.
|
||||
std::string after;
|
||||
slurp (file.str (), after, false);
|
||||
File::read (file.str (), after);
|
||||
|
||||
// Update task based on what can be parsed back out of the file, but only
|
||||
// if changes were made.
|
||||
|
@ -582,7 +584,7 @@ ARE_THESE_REALLY_HARMFUL:
|
|||
|
||||
// Preserve the edits.
|
||||
before = after;
|
||||
spit (file.str (), before);
|
||||
File::write (file.str (), before);
|
||||
|
||||
if (confirm ("Task couldn't handle your edits. Would you like to try again?"))
|
||||
goto ARE_THESE_REALLY_HARMFUL;
|
||||
|
@ -592,7 +594,7 @@ ARE_THESE_REALLY_HARMFUL:
|
|||
std::cout << "No edits were detected." << std::endl;
|
||||
|
||||
// Cleanup.
|
||||
unlink (file.str ().c_str ());
|
||||
File::remove (file.str ());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -604,7 +606,7 @@ int handleEdit (std::string &outs)
|
|||
std::stringstream out;
|
||||
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
handleRecurrence ();
|
||||
Filter filter;
|
||||
context.tdb.loadPending (tasks, filter);
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <sstream>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "File.h"
|
||||
#include "Date.h"
|
||||
#include "text.h"
|
||||
#include "util.h"
|
||||
|
@ -168,12 +169,12 @@ static void decorateTask (Task& task)
|
|||
task.setStatus (Task::pending);
|
||||
|
||||
// Override with default.project, if not specified.
|
||||
std::string defaultProject = context.config.get ("default.project", "");
|
||||
std::string defaultProject = context.config.get ("default.project");
|
||||
if (!task.has ("project") && defaultProject != "")
|
||||
task.set ("project", defaultProject);
|
||||
|
||||
// Override with default.priority, if not specified.
|
||||
std::string defaultPriority = context.config.get ("default.priority", "");
|
||||
std::string defaultPriority = context.config.get ("default.priority");
|
||||
if (!task.has ("priority") &&
|
||||
defaultPriority != "" &&
|
||||
Att::validNameValue ("priority", "", defaultPriority))
|
||||
|
@ -185,7 +186,7 @@ static std::string importTask_1_4_3 (const std::vector <std::string>& lines)
|
|||
{
|
||||
std::vector <std::string> failed;
|
||||
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
|
||||
std::vector <std::string>::const_iterator it;
|
||||
for (it = lines.begin (); it != lines.end (); ++it)
|
||||
|
@ -342,7 +343,7 @@ static std::string importTask_1_5_0 (const std::vector <std::string>& lines)
|
|||
{
|
||||
std::vector <std::string> failed;
|
||||
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
|
||||
std::vector <std::string>::const_iterator it;
|
||||
for (it = lines.begin (); it != lines.end (); ++it)
|
||||
|
@ -504,7 +505,7 @@ static std::string importTask_1_6_0 (const std::vector <std::string>& lines)
|
|||
{
|
||||
std::vector <std::string> failed;
|
||||
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
|
||||
std::vector <std::string>::const_iterator it;
|
||||
for (it = lines.begin (); it != lines.end (); ++it)
|
||||
|
@ -715,7 +716,7 @@ static std::string importTodoSh_2_0 (const std::vector <std::string>& lines)
|
|||
{
|
||||
std::vector <std::string> failed;
|
||||
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
|
||||
std::vector <std::string>::const_iterator it;
|
||||
for (it = lines.begin (); it != lines.end (); ++it)
|
||||
|
@ -840,7 +841,7 @@ static std::string importText (const std::vector <std::string>& lines)
|
|||
std::vector <std::string> failed;
|
||||
int count = 0;
|
||||
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
|
||||
std::vector <std::string>::const_iterator it;
|
||||
for (it = lines.begin (); it != lines.end (); ++it)
|
||||
|
@ -904,7 +905,7 @@ static std::string importCSV (const std::vector <std::string>& lines)
|
|||
{
|
||||
std::vector <std::string> failed;
|
||||
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
|
||||
// Set up mappings. Assume no fields match.
|
||||
std::map <std::string, int> mapping;
|
||||
|
@ -1155,7 +1156,7 @@ int handleImport (std::string &outs)
|
|||
{
|
||||
// Load the file.
|
||||
std::vector <std::string> all;
|
||||
slurp (file, all, true);
|
||||
File::read (file, all);
|
||||
|
||||
std::vector <std::string> lines;
|
||||
std::vector <std::string>::iterator it;
|
||||
|
|
|
@ -137,10 +137,10 @@ int Context::interactive ()
|
|||
int Context::getWidth ()
|
||||
{
|
||||
// Determine window size, and set table accordingly.
|
||||
int width = config.get ("defaultwidth", (int) 80);
|
||||
int width = config.getInteger ("defaultwidth");
|
||||
|
||||
#ifdef HAVE_LIBNCURSES
|
||||
if (config.get ("curses", true))
|
||||
if (config.getBoolean ("curses"))
|
||||
{
|
||||
#ifdef FEATURE_NCURSES_COLS
|
||||
initscr ();
|
||||
|
|
|
@ -103,7 +103,7 @@ int handleReportCalendar (std::string &);
|
|||
int handleReportStats (std::string &);
|
||||
int handleReportTimesheet (std::string &);
|
||||
std::string getFullDescription (Task&);
|
||||
std::string getDueDate (Task&);
|
||||
std::string getDueDate (Task&, const std::string&);
|
||||
|
||||
// custom.cpp
|
||||
int handleCustomReport (const std::string&, std::string &);
|
||||
|
|
|
@ -390,7 +390,7 @@ int getDueState (const std::string& due)
|
|||
if (dt < thisDay)
|
||||
return 2;
|
||||
|
||||
int imminentperiod = context.config.get ("due", 7);
|
||||
int imminentperiod = context.config.getInteger ("due");
|
||||
|
||||
if (imminentperiod == 0)
|
||||
return 1;
|
||||
|
@ -406,7 +406,7 @@ int getDueState (const std::string& due)
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool nag (Task& task)
|
||||
{
|
||||
std::string nagMessage = context.config.get ("nag", "");
|
||||
std::string nagMessage = context.config.get ("nag");
|
||||
if (nagMessage != "")
|
||||
{
|
||||
// Load all pending tasks.
|
||||
|
|
232
src/report.cpp
232
src/report.cpp
|
@ -1,7 +1,7 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// task - a command line task list manager.
|
||||
//
|
||||
// Copyright 2006 - 2010, Paul Beckingham.
|
||||
// Copyright 2006 - 2010, Paul Beckingham, Federico Hernandez.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify it under
|
||||
|
@ -29,7 +29,6 @@
|
|||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -37,6 +36,8 @@
|
|||
#include <time.h>
|
||||
|
||||
#include "Context.h"
|
||||
#include "Directory.h"
|
||||
#include "File.h"
|
||||
#include "Date.h"
|
||||
#include "Table.h"
|
||||
#include "text.h"
|
||||
|
@ -66,7 +67,7 @@ int shortUsage (std::string &outs)
|
|||
table.setColumnWidth (1, Table::minimum);
|
||||
table.setColumnWidth (2, Table::flexible);
|
||||
table.setTableWidth (context.getWidth ());
|
||||
table.setDateFormat (context.config.get ("dateformat", "m/d/Y"));
|
||||
table.setDateFormat (context.config.get ("dateformat"));
|
||||
|
||||
int row = table.addRow ();
|
||||
table.addCell (row, 0, "Usage:");
|
||||
|
@ -186,8 +187,8 @@ int shortUsage (std::string &outs)
|
|||
table.addCell (row, 2, "Shows the task version number.");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task config");
|
||||
table.addCell (row, 2, "Shows the task configuration.");
|
||||
table.addCell (row, 1, "task config [name [value | '']]");
|
||||
table.addCell (row, 2, "Shows the task configuration, or can add, modify and remove settings.");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task help");
|
||||
|
@ -199,8 +200,9 @@ int shortUsage (std::string &outs)
|
|||
foreach (report, all)
|
||||
{
|
||||
std::string command = std::string ("task ") + *report + std::string (" [tags] [attrs] desc...");
|
||||
std::string description = context.config.get (
|
||||
std::string ("report.") + *report + ".description", std::string ("(missing description)"));
|
||||
std::string description = context.config.get (std::string ("report.") + *report + ".description");
|
||||
if (description == "")
|
||||
description = "(missing description)";
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, command);
|
||||
|
@ -300,7 +302,7 @@ int handleInfo (std::string &outs)
|
|||
int rc = 0;
|
||||
// Get all the tasks.
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
handleRecurrence ();
|
||||
context.tdb.loadPending (tasks, context.filter);
|
||||
context.tdb.commit ();
|
||||
|
@ -315,13 +317,13 @@ int handleInfo (std::string &outs)
|
|||
{
|
||||
Table table;
|
||||
table.setTableWidth (context.getWidth ());
|
||||
table.setDateFormat (context.config.get ("dateformat", "m/d/Y"));
|
||||
table.setDateFormat (context.config.get ("dateformat"));
|
||||
|
||||
table.addColumn ("Name");
|
||||
table.addColumn ("Value");
|
||||
|
||||
if ((context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false)) &&
|
||||
context.config.get (std::string ("fontunderline"), "true"))
|
||||
if ((context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor")) &&
|
||||
context.config.getBoolean ("fontunderline"))
|
||||
{
|
||||
table.setColumnUnderline (0);
|
||||
table.setColumnUnderline (1);
|
||||
|
@ -412,20 +414,24 @@ int handleInfo (std::string &outs)
|
|||
table.addCell (row, 0, "Due");
|
||||
|
||||
Date dt (atoi (task->get ("due").c_str ()));
|
||||
std::string due = getDueDate (*task);
|
||||
std::string format = context.config.get ("reportdateformat");
|
||||
if (format == "")
|
||||
format = context.config.get ("dateformat");
|
||||
|
||||
std::string due = getDueDate (*task, format);
|
||||
table.addCell (row, 1, due);
|
||||
|
||||
overdue = (dt < now) ? true : false;
|
||||
int imminentperiod = context.config.get ("due", 7);
|
||||
int imminentperiod = context.config.getInteger ("due");
|
||||
Date imminentDay = now + imminentperiod * 86400;
|
||||
imminent = dt < imminentDay ? true : false;
|
||||
|
||||
if (context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false))
|
||||
if (context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
||||
{
|
||||
if (overdue)
|
||||
table.setCellColor (row, 1, Color (context.config.get ("color.overdue", "red")));
|
||||
table.setCellColor (row, 1, Color (context.config.get ("color.overdue")));
|
||||
else if (imminent)
|
||||
table.setCellColor (row, 1, Color (context.config.get ("color.due", "green")));
|
||||
table.setCellColor (row, 1, Color (context.config.get ("color.due")));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -435,7 +441,7 @@ int handleInfo (std::string &outs)
|
|||
row = table.addRow ();
|
||||
table.addCell (row, 0, "Waiting until");
|
||||
Date dt (atoi (task->get ("wait").c_str ()));
|
||||
table.addCell (row, 1, dt.toString (context.config.get ("dateformat", "m/d/Y")));
|
||||
table.addCell (row, 1, dt.toString (context.config.get ("dateformat")));
|
||||
}
|
||||
|
||||
// start
|
||||
|
@ -444,7 +450,7 @@ int handleInfo (std::string &outs)
|
|||
row = table.addRow ();
|
||||
table.addCell (row, 0, "Start");
|
||||
Date dt (atoi (task->get ("start").c_str ()));
|
||||
table.addCell (row, 1, dt.toString (context.config.get ("dateformat", "m/d/Y")));
|
||||
table.addCell (row, 1, dt.toString (context.config.get ("dateformat")));
|
||||
}
|
||||
|
||||
// end
|
||||
|
@ -453,7 +459,7 @@ int handleInfo (std::string &outs)
|
|||
row = table.addRow ();
|
||||
table.addCell (row, 0, "End");
|
||||
Date dt (atoi (task->get ("end").c_str ()));
|
||||
table.addCell (row, 1, dt.toString (context.config.get ("dateformat", "m/d/Y")));
|
||||
table.addCell (row, 1, dt.toString (context.config.get ("dateformat")));
|
||||
}
|
||||
|
||||
// tags ...
|
||||
|
@ -478,7 +484,7 @@ int handleInfo (std::string &outs)
|
|||
row = table.addRow ();
|
||||
table.addCell (row, 0, "Entered");
|
||||
Date dt (atoi (task->get ("entry").c_str ()));
|
||||
std::string entry = dt.toString (context.config.get ("dateformat", "m/d/Y"));
|
||||
std::string entry = dt.toString (context.config.get ("dateformat"));
|
||||
|
||||
std::string age;
|
||||
std::string created = task->get ("entry");
|
||||
|
@ -531,7 +537,7 @@ int handleReportSummary (std::string &outs)
|
|||
int rc = 0;
|
||||
// Scan the pending tasks.
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
handleRecurrence ();
|
||||
context.tdb.load (tasks, context.filter);
|
||||
context.tdb.commit ();
|
||||
|
@ -594,8 +600,8 @@ int handleReportSummary (std::string &outs)
|
|||
table.addColumn ("Complete");
|
||||
table.addColumn ("0% 100%");
|
||||
|
||||
if ((context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false)) &&
|
||||
context.config.get (std::string ("fontunderline"), "true"))
|
||||
if ((context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor")) &&
|
||||
context.config.getBoolean ("fontunderline"))
|
||||
{
|
||||
table.setColumnUnderline (0);
|
||||
table.setColumnUnderline (1);
|
||||
|
@ -610,7 +616,7 @@ int handleReportSummary (std::string &outs)
|
|||
table.setColumnJustification (3, Table::right);
|
||||
|
||||
table.sortOn (0, Table::ascendingCharacter);
|
||||
table.setDateFormat (context.config.get ("dateformat", "m/d/Y"));
|
||||
table.setDateFormat (context.config.get ("dateformat"));
|
||||
|
||||
int barWidth = 30;
|
||||
foreach (i, allProjects)
|
||||
|
@ -632,7 +638,7 @@ int handleReportSummary (std::string &outs)
|
|||
int completedBar = (c * barWidth) / (c + p);
|
||||
|
||||
std::string bar;
|
||||
if (context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false))
|
||||
if (context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
||||
{
|
||||
bar = "\033[42m";
|
||||
for (int b = 0; b < completedBar; ++b)
|
||||
|
@ -726,7 +732,7 @@ int handleReportNext (std::string &outs)
|
|||
|
||||
// Get all the tasks.
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
handleRecurrence ();
|
||||
context.tdb.load (tasks, context.filter);
|
||||
context.tdb.commit ();
|
||||
|
@ -778,7 +784,7 @@ int handleReportHistory (std::string &outs)
|
|||
|
||||
// Scan the pending tasks.
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
handleRecurrence ();
|
||||
context.tdb.load (tasks, context.filter);
|
||||
context.tdb.commit ();
|
||||
|
@ -822,7 +828,7 @@ int handleReportHistory (std::string &outs)
|
|||
|
||||
// Now build the table.
|
||||
Table table;
|
||||
table.setDateFormat (context.config.get ("dateformat", "m/d/Y"));
|
||||
table.setDateFormat (context.config.get ("dateformat"));
|
||||
table.addColumn ("Year");
|
||||
table.addColumn ("Month");
|
||||
table.addColumn ("Added");
|
||||
|
@ -830,8 +836,8 @@ int handleReportHistory (std::string &outs)
|
|||
table.addColumn ("Deleted");
|
||||
table.addColumn ("Net");
|
||||
|
||||
if ((context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false)) &&
|
||||
context.config.get (std::string ("fontunderline"), "true"))
|
||||
if ((context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor")) &&
|
||||
context.config.getBoolean ("fontunderline"))
|
||||
{
|
||||
table.setColumnUnderline (0);
|
||||
table.setColumnUnderline (1);
|
||||
|
@ -894,7 +900,7 @@ int handleReportHistory (std::string &outs)
|
|||
}
|
||||
|
||||
table.addCell (row, 5, net);
|
||||
if ((context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false)) && net)
|
||||
if ((context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor")) && net)
|
||||
table.setCellColor (row, 5, net > 0 ? Color (Color::red) :
|
||||
Color (Color::green));
|
||||
}
|
||||
|
@ -905,7 +911,7 @@ int handleReportHistory (std::string &outs)
|
|||
row = table.addRow ();
|
||||
|
||||
table.addCell (row, 1, "Average");
|
||||
if (context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false))
|
||||
if (context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
||||
table.setRowColor (row, Color (Color::nocolor, Color::nocolor, false, true, false));
|
||||
table.addCell (row, 2, totalAdded / (table.rowCount () - 2));
|
||||
table.addCell (row, 3, totalCompleted / (table.rowCount () - 2));
|
||||
|
@ -938,7 +944,7 @@ int handleReportGHistory (std::string &outs)
|
|||
|
||||
// Scan the pending tasks.
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
handleRecurrence ();
|
||||
context.tdb.load (tasks, context.filter);
|
||||
context.tdb.commit ();
|
||||
|
@ -984,13 +990,13 @@ int handleReportGHistory (std::string &outs)
|
|||
|
||||
// Now build the table.
|
||||
Table table;
|
||||
table.setDateFormat (context.config.get ("dateformat", "m/d/Y"));
|
||||
table.setDateFormat (context.config.get ("dateformat"));
|
||||
table.addColumn ("Year");
|
||||
table.addColumn ("Month");
|
||||
table.addColumn ("Number Added/Completed/Deleted");
|
||||
|
||||
if ((context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false)) &&
|
||||
context.config.get (std::string ("fontunderline"), "true"))
|
||||
if ((context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor")) &&
|
||||
context.config.getBoolean ("fontunderline"))
|
||||
{
|
||||
table.setColumnUnderline (0);
|
||||
table.setColumnUnderline (1);
|
||||
|
@ -1049,7 +1055,7 @@ int handleReportGHistory (std::string &outs)
|
|||
unsigned int deletedBar = (widthOfBar * deletedGroup[i->first]) / maxLine;
|
||||
|
||||
std::string bar = "";
|
||||
if (context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false))
|
||||
if (context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
||||
{
|
||||
char number[24];
|
||||
std::string aBar = "";
|
||||
|
@ -1109,7 +1115,7 @@ int handleReportGHistory (std::string &outs)
|
|||
<< table.render ()
|
||||
<< std::endl;
|
||||
|
||||
if (context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false))
|
||||
if (context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
||||
out << "Legend: "
|
||||
<< color_added.colorize ("added")
|
||||
<< ", "
|
||||
|
@ -1135,7 +1141,7 @@ int handleReportTimesheet (std::string &outs)
|
|||
{
|
||||
// Scan the pending tasks.
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
handleRecurrence ();
|
||||
context.tdb.load (tasks, context.filter);
|
||||
context.tdb.commit ();
|
||||
|
@ -1145,7 +1151,7 @@ int handleReportTimesheet (std::string &outs)
|
|||
int width = context.getWidth ();
|
||||
|
||||
// What day of the week does the user consider the first?
|
||||
int weekStart = Date::dayOfWeek (context.config.get ("weekstart", "Sunday"));
|
||||
int weekStart = Date::dayOfWeek (context.config.get ("weekstart"));
|
||||
if (weekStart != 0 && weekStart != 1)
|
||||
throw std::string ("The 'weekstart' configuration variable may "
|
||||
"only contain 'Sunday' or 'Monday'.");
|
||||
|
@ -1164,7 +1170,7 @@ int handleReportTimesheet (std::string &outs)
|
|||
if (context.sequence.size () == 1)
|
||||
quantity = context.sequence[0];
|
||||
|
||||
bool color = context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false);
|
||||
bool color = context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor");
|
||||
|
||||
std::stringstream out;
|
||||
for (int week = 0; week < quantity; ++week)
|
||||
|
@ -1172,9 +1178,9 @@ int handleReportTimesheet (std::string &outs)
|
|||
Date endString (end);
|
||||
endString -= 86400;
|
||||
|
||||
std::string title = start.toString (context.config.get ("dateformat", "m/d/Y"))
|
||||
std::string title = start.toString (context.config.get ("dateformat"))
|
||||
+ " - "
|
||||
+ endString.toString (context.config.get ("dateformat", "m/d/Y"));
|
||||
+ endString.toString (context.config.get ("dateformat"));
|
||||
|
||||
Color bold (Color::nocolor, Color::nocolor, false, true, false);
|
||||
out << std::endl
|
||||
|
@ -1189,7 +1195,7 @@ int handleReportTimesheet (std::string &outs)
|
|||
completed.addColumn ("Due");
|
||||
completed.addColumn ("Description");
|
||||
|
||||
if (color && context.config.get (std::string ("fontunderline"), "true"))
|
||||
if (color && context.config.getBoolean ("fontunderline"))
|
||||
{
|
||||
completed.setColumnUnderline (1);
|
||||
completed.setColumnUnderline (2);
|
||||
|
@ -1218,7 +1224,7 @@ int handleReportTimesheet (std::string &outs)
|
|||
{
|
||||
int row = completed.addRow ();
|
||||
completed.addCell (row, 1, task->get ("project"));
|
||||
completed.addCell (row, 2, getDueDate (*task));
|
||||
completed.addCell (row, 2, getDueDate (*task, context.config.get("dateformat")));
|
||||
completed.addCell (row, 3, getFullDescription (*task));
|
||||
|
||||
if (color)
|
||||
|
@ -1245,7 +1251,7 @@ int handleReportTimesheet (std::string &outs)
|
|||
started.addColumn ("Due");
|
||||
started.addColumn ("Description");
|
||||
|
||||
if (color && context.config.get (std::string ("fontunderline"), "true"))
|
||||
if (color && context.config.getBoolean ("fontunderline"))
|
||||
{
|
||||
completed.setColumnUnderline (1);
|
||||
completed.setColumnUnderline (2);
|
||||
|
@ -1274,7 +1280,7 @@ int handleReportTimesheet (std::string &outs)
|
|||
{
|
||||
int row = started.addRow ();
|
||||
started.addCell (row, 1, task->get ("project"));
|
||||
started.addCell (row, 2, getDueDate (*task));
|
||||
started.addCell (row, 2, getDueDate (*task, context.config.get ("dateformat")));
|
||||
started.addCell (row, 3, getFullDescription (*task));
|
||||
|
||||
if (color)
|
||||
|
@ -1312,10 +1318,10 @@ std::string renderMonths (
|
|||
int monthsPerLine)
|
||||
{
|
||||
Table table;
|
||||
table.setDateFormat (context.config.get ("dateformat", "m/d/Y"));
|
||||
table.setDateFormat (context.config.get ("dateformat"));
|
||||
|
||||
// What day of the week does the user consider the first?
|
||||
int weekStart = Date::dayOfWeek (context.config.get ("weekstart", "Sunday"));
|
||||
int weekStart = Date::dayOfWeek (context.config.get ("weekstart"));
|
||||
if (weekStart != 0 && weekStart != 1)
|
||||
throw std::string ("The 'weekstart' configuration variable may "
|
||||
"only contain 'Sunday' or 'Monday'.");
|
||||
|
@ -1346,8 +1352,8 @@ std::string renderMonths (
|
|||
table.addColumn ("Sa");
|
||||
}
|
||||
|
||||
if ((context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false)) &&
|
||||
context.config.get (std::string ("fontunderline"), "true"))
|
||||
if ((context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor")) &&
|
||||
context.config.getBoolean ("fontunderline"))
|
||||
{
|
||||
table.setColumnUnderline (i + 1);
|
||||
table.setColumnUnderline (i + 2);
|
||||
|
@ -1418,7 +1424,7 @@ std::string renderMonths (
|
|||
int dow = temp.dayOfWeek ();
|
||||
int woy = temp.weekOfYear (weekStart);
|
||||
|
||||
if (context.config.get ("displayweeknumber", true))
|
||||
if (context.config.getBoolean ("displayweeknumber"))
|
||||
table.addCell (row, (8 * mpl), woy);
|
||||
|
||||
// Calculate column id.
|
||||
|
@ -1431,12 +1437,12 @@ std::string renderMonths (
|
|||
|
||||
table.addCell (row, thisCol, d);
|
||||
|
||||
Color color_today (context.config.get ("color.calendar.today", "black on cyan"));
|
||||
Color color_due (context.config.get ("color.calendar.due", "black on green"));
|
||||
Color color_overdue (context.config.get ("color.calendar.overdue", "black on red"));
|
||||
Color color_weekend (context.config.get ("color.calendar.weekend", "black on white"));
|
||||
Color color_today (context.config.get ("color.calendar.today"));
|
||||
Color color_due (context.config.get ("color.calendar.due"));
|
||||
Color color_overdue (context.config.get ("color.calendar.overdue"));
|
||||
Color color_weekend (context.config.get ("color.calendar.weekend"));
|
||||
|
||||
if (context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false))
|
||||
if (context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
||||
{
|
||||
if (dow == 0 || dow == 6)
|
||||
table.setCellColor (row, thisCol, color_weekend);
|
||||
|
@ -1454,7 +1460,7 @@ std::string renderMonths (
|
|||
{
|
||||
Date due (atoi (task->get ("due").c_str ()));
|
||||
|
||||
if ((context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false)) &&
|
||||
if ((context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor")) &&
|
||||
due.day () == d &&
|
||||
due.month () == months[mpl] &&
|
||||
due.year () == years[mpl])
|
||||
|
@ -1480,7 +1486,7 @@ int handleReportCalendar (std::string &outs)
|
|||
// Each month requires 28 text columns width. See how many will actually
|
||||
// fit. But if a preference is specified, and it fits, use it.
|
||||
int width = context.getWidth ();
|
||||
int preferredMonthsPerLine = (context.config.get (std::string ("monthsperline"), 0));
|
||||
int preferredMonthsPerLine = (context.config.getInteger ("monthsperline"));
|
||||
int monthsThatFit = width / 26;
|
||||
|
||||
int monthsPerLine = monthsThatFit;
|
||||
|
@ -1490,7 +1496,7 @@ int handleReportCalendar (std::string &outs)
|
|||
// Get all the tasks.
|
||||
std::vector <Task> tasks;
|
||||
Filter filter;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
handleRecurrence ();
|
||||
context.tdb.loadPending (tasks, filter);
|
||||
context.tdb.commit ();
|
||||
|
@ -1529,7 +1535,7 @@ int handleReportCalendar (std::string &outs)
|
|||
// task cal 2010
|
||||
monthsToDisplay = 12;
|
||||
mFrom = 1;
|
||||
yFrom = atoi( context.args[1].data());
|
||||
yFrom = atoi (context.args[1].c_str ());
|
||||
}
|
||||
}
|
||||
else if (numberOfArgs == 3) {
|
||||
|
@ -1541,15 +1547,15 @@ int handleReportCalendar (std::string &outs)
|
|||
else {
|
||||
// task cal 8 2010
|
||||
monthsToDisplay = monthsPerLine;
|
||||
mFrom = atoi( context.args[1].data());
|
||||
yFrom = atoi( context.args[2].data());
|
||||
mFrom = atoi (context.args[1].c_str ());
|
||||
yFrom = atoi (context.args[2].c_str ());
|
||||
}
|
||||
}
|
||||
else if (numberOfArgs == 4) {
|
||||
// task cal 8 2010 y
|
||||
monthsToDisplay = 12;
|
||||
mFrom = atoi( context.args[1].data());
|
||||
yFrom = atoi( context.args[2].data());
|
||||
mFrom = atoi (context.args[1].c_str ());
|
||||
yFrom = atoi (context.args[2].c_str ());
|
||||
}
|
||||
|
||||
int countDueDates = 0;
|
||||
|
@ -1640,12 +1646,12 @@ int handleReportCalendar (std::string &outs)
|
|||
}
|
||||
}
|
||||
|
||||
Color color_today (context.config.get ("color.calendar.today", "black on cyan"));
|
||||
Color color_due (context.config.get ("color.calendar.due", "black on green"));
|
||||
Color color_overdue (context.config.get ("color.calendar.overdue", "black on red"));
|
||||
Color color_weekend (context.config.get ("color.calendar.weekend", "black on white"));
|
||||
Color color_today (context.config.get ("color.calendar.today"));
|
||||
Color color_due (context.config.get ("color.calendar.due"));
|
||||
Color color_overdue (context.config.get ("color.calendar.overdue"));
|
||||
Color color_weekend (context.config.get ("color.calendar.weekend"));
|
||||
|
||||
if (context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false))
|
||||
if (context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
||||
out << "Legend: "
|
||||
<< color_today.colorize ("today")
|
||||
<< ", "
|
||||
|
@ -1658,7 +1664,7 @@ int handleReportCalendar (std::string &outs)
|
|||
<< optionalBlankLine ()
|
||||
<< std::endl;
|
||||
|
||||
if (context.config.get (std::string ("calendar.details"), false))
|
||||
if (context.config.getBoolean ("calendar.details"))
|
||||
{
|
||||
--details_mFrom;
|
||||
if (details_mFrom == 0)
|
||||
|
@ -1676,12 +1682,12 @@ int handleReportCalendar (std::string &outs)
|
|||
}
|
||||
|
||||
Date date_after (details_mFrom, details_dFrom, details_yFrom);
|
||||
std::string after = date_after.toString (context.config.get ("dateformat", "m/d/Y"));
|
||||
|
||||
Date date_before (mTo, 1, yTo);
|
||||
std::string before = date_before.toString (context.config.get ("dateformat", "m/d/Y"));
|
||||
std::string after = date_after.toString (context.config.get ("dateformat"));
|
||||
|
||||
std::string report = context.config.get ("calendar.details.report", "list");
|
||||
Date date_before (mTo, 1, yTo);
|
||||
std::string before = date_before.toString (context.config.get ("dateformat"));
|
||||
|
||||
std::string report = context.config.get ("calendar.details.report");
|
||||
std::string report_filter = context.config.get ("report." + report + ".filter");
|
||||
|
||||
report_filter += " due.after:" + after + " due.before:" + before;
|
||||
|
@ -1711,30 +1717,26 @@ int handleReportStats (std::string &outs)
|
|||
// Go get the file sizes.
|
||||
size_t dataSize = 0;
|
||||
|
||||
struct stat s;
|
||||
std::string location = expandPath (context.config.get ("data.location"));
|
||||
std::string file = location + "/pending.data";
|
||||
if (!stat (file.c_str (), &s))
|
||||
dataSize += s.st_size;
|
||||
Directory location (context.config.get ("data.location"));
|
||||
File pending (location.data + "/pending.data");
|
||||
dataSize += pending.size ();
|
||||
|
||||
file = location + "/completed.data";
|
||||
if (!stat (file.c_str (), &s))
|
||||
dataSize += s.st_size;
|
||||
File completed (location.data + "/completed.data");
|
||||
dataSize += completed.size ();
|
||||
|
||||
file = location + "/undo.data";
|
||||
if (!stat (file.c_str (), &s))
|
||||
dataSize += s.st_size;
|
||||
File undo (location.data + "/undo.data");
|
||||
dataSize += undo.size ();
|
||||
|
||||
std::vector <std::string> undo;
|
||||
slurp (file, undo, false);
|
||||
std::vector <std::string> undoTxns;
|
||||
File::read (undo, undoTxns);
|
||||
int undoCount = 0;
|
||||
foreach (tx, undo)
|
||||
foreach (tx, undoTxns)
|
||||
if (tx->substr (0, 3) == "---")
|
||||
++undoCount;
|
||||
|
||||
// Get all the tasks.
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.get ("locking", true));
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
handleRecurrence ();
|
||||
context.tdb.load (tasks, context.filter);
|
||||
context.tdb.commit ();
|
||||
|
@ -1801,12 +1803,12 @@ int handleReportStats (std::string &outs)
|
|||
Table table;
|
||||
table.setTableWidth (context.getWidth ());
|
||||
table.setTableIntraPadding (2);
|
||||
table.setDateFormat (context.config.get ("dateformat", "m/d/Y"));
|
||||
table.setDateFormat (context.config.get ("dateformat"));
|
||||
table.addColumn ("Category");
|
||||
table.addColumn ("Data");
|
||||
|
||||
if ((context.config.get ("color", true) || context.config.get (std::string ("_forcecolor"), false)) &&
|
||||
context.config.get (std::string ("fontunderline"), "true"))
|
||||
if ((context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor")) &&
|
||||
context.config.getBoolean ("fontunderline"))
|
||||
{
|
||||
table.setColumnUnderline (0);
|
||||
table.setColumnUnderline (1);
|
||||
|
@ -1879,12 +1881,12 @@ int handleReportStats (std::string &outs)
|
|||
Date e (earliest);
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 0, "Oldest task");
|
||||
table.addCell (row, 1, e.toString (context.config.get ("dateformat", "m/d/Y")));
|
||||
table.addCell (row, 1, e.toString (context.config.get ("dateformat")));
|
||||
|
||||
Date l (latest);
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 0, "Newest task");
|
||||
table.addCell (row, 1, l.toString (context.config.get ("dateformat", "m/d/Y")));
|
||||
table.addCell (row, 1, l.toString (context.config.get ("dateformat")));
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 0, "Task used for");
|
||||
|
@ -1946,7 +1948,7 @@ void gatherNextTasks (std::vector <Task>& tasks)
|
|||
Date now;
|
||||
|
||||
// How many items per project? Default 2.
|
||||
int limit = context.config.get ("next", 2);
|
||||
int limit = context.config.getInteger ("next");
|
||||
|
||||
// due:< 1wk, pri:*
|
||||
foreach (task, tasks)
|
||||
|
@ -2113,24 +2115,44 @@ std::string getFullDescription (Task& task)
|
|||
|
||||
std::vector <Att> annotations;
|
||||
task.getAnnotations (annotations);
|
||||
foreach (anno, annotations)
|
||||
{
|
||||
Date dt (atoi (anno->name ().substr (11).c_str ()));
|
||||
std::string when = dt.toString (context.config.get ("dateformat", "m/d/Y"));
|
||||
desc += "\n" + when + " " + anno->value ();
|
||||
}
|
||||
|
||||
if (annotations.size () != 0)
|
||||
switch (context.config.getInteger ("annotation.details"))
|
||||
{
|
||||
case 0:
|
||||
desc = "+" + desc;
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
if (annotations.size () > 1)
|
||||
desc = "+" + desc;
|
||||
Att anno (annotations.back());
|
||||
Date dt (atoi (anno.name ().substr (11).c_str ()));
|
||||
std::string when = dt.toString (context.config.get ("dateformat"));
|
||||
desc += "\n" + when + " " + anno.value ();
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
foreach (anno, annotations)
|
||||
{
|
||||
Date dt (atoi (anno->name ().substr (11).c_str ()));
|
||||
std::string when = dt.toString (context.config.get ("dateformat"));
|
||||
desc += "\n" + when + " " + anno->value ();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
std::string getDueDate (Task& task)
|
||||
std::string getDueDate (Task& task, const std::string& format)
|
||||
{
|
||||
std::string due = task.get ("due");
|
||||
if (due.length ())
|
||||
{
|
||||
Date d (atoi (due.c_str ()));
|
||||
due = d.toString (context.config.get ("dateformat", "m/d/Y"));
|
||||
due = d.toString (format);
|
||||
}
|
||||
|
||||
return due;
|
||||
|
|
|
@ -33,7 +33,8 @@ use Test::More tests => 13;
|
|||
# Create the rc file.
|
||||
if (open my $fh, '>', 'add.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
print $fh "data.location=.\n",
|
||||
"confirmation=off\n";
|
||||
close $fh;
|
||||
ok (-r 'add.rc', 'Created add.rc');
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 9;
|
||||
use Test::More tests => 37;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'annotate.rc')
|
||||
|
@ -36,6 +36,7 @@ if (open my $fh, '>', 'annotate.rc')
|
|||
# Note: Use 'rrr' to guarantee a unique report name. Using 'r' conflicts
|
||||
# with 'recurring'.
|
||||
print $fh "data.location=.\n",
|
||||
"confirmation=off\n",
|
||||
"report.rrr.description=rrr\n",
|
||||
"report.rrr.columns=id,description\n",
|
||||
"report.rrr.sort=id+\n";
|
||||
|
@ -43,27 +44,76 @@ if (open my $fh, '>', 'annotate.rc')
|
|||
ok (-r 'annotate.rc', 'Created annotate.rc');
|
||||
}
|
||||
|
||||
# Add two tasks, annotate one twice.
|
||||
# Add four tasks, annotate one three times, one twice, one just once and one none.
|
||||
qx{../task rc:annotate.rc add one};
|
||||
qx{../task rc:annotate.rc add two};
|
||||
qx{../task rc:annotate.rc annotate 1 foo};
|
||||
sleep 2;
|
||||
qx{../task rc:annotate.rc annotate 1 bar};
|
||||
qx{../task rc:annotate.rc add three};
|
||||
qx{../task rc:annotate.rc add four};
|
||||
qx{../task rc:annotate.rc annotate 1 foo1};
|
||||
sleep 1;
|
||||
qx{../task rc:annotate.rc annotate 1 foo2};
|
||||
sleep 1;
|
||||
qx{../task rc:annotate.rc annotate 1 foo3};
|
||||
sleep 1;
|
||||
qx{../task rc:annotate.rc annotate 2 bar1};
|
||||
sleep 1;
|
||||
qx{../task rc:annotate.rc annotate 2 bar2};
|
||||
sleep 1;
|
||||
qx{../task rc:annotate.rc annotate 3 baz1};
|
||||
|
||||
my $output = qx{../task rc:annotate.rc rrr};
|
||||
|
||||
# ID Description
|
||||
# -- -------------------------------
|
||||
# 1 one
|
||||
# 3/24/2009 foo
|
||||
# 3/24/2009 bar
|
||||
# 3/24/2009 foo1
|
||||
# 3/24/2009 foo2
|
||||
# 3/24/2009 foo3
|
||||
# 2 two
|
||||
# 3/24/2009 bar1
|
||||
# 3/24/2009 bar2
|
||||
# 3 three
|
||||
# 3/24/2009 baz1
|
||||
# 4 four
|
||||
#
|
||||
# 2 tasks
|
||||
# 4 tasks
|
||||
like ($output, qr/1 one/, 'task 1');
|
||||
like ($output, qr/2 two/, 'task 2');
|
||||
like ($output, qr/one.+\d{1,2}\/\d{1,2}\/\d{4} foo/ms, 'first annotation');
|
||||
like ($output, qr/foo.+\d{1,2}\/\d{1,2}\/\d{4} bar/ms, 'second annotation');
|
||||
like ($output, qr/2 tasks/, 'count');
|
||||
like ($output, qr/3 three/, 'task 3');
|
||||
like ($output, qr/4 four/, 'task 4');
|
||||
like ($output, qr/one.+\d{1,2}\/\d{1,2}\/\d{4} foo1/ms, 'first annotation task 1');
|
||||
like ($output, qr/foo1.+\d{1,2}\/\d{1,2}\/\d{4} foo2/ms, 'second annotation task 1');
|
||||
like ($output, qr/foo2.+\d{1,2}\/\d{1,2}\/\d{4} foo3/ms, 'third annotation task 1');
|
||||
like ($output, qr/two.+\d{1,2}\/\d{1,2}\/\d{4} bar1/ms, 'first annotation task 2');
|
||||
like ($output, qr/bar1.+\d{1,2}\/\d{1,2}\/\d{4} bar2/ms, 'second annotation task 2');
|
||||
like ($output, qr/three.+\d{1,2}\/\d{1,2}\/\d{4} baz1/ms,'first annotation task 3');
|
||||
like ($output, qr/4 tasks/, 'count');
|
||||
|
||||
$output = qx{../task rc:annotate.rc rc.annotation.details:1 rrr};
|
||||
like ($output, qr/1 \+one/, 'task 1');
|
||||
like ($output, qr/2 \+two/, 'task 2');
|
||||
like ($output, qr/3 three/, 'task 3');
|
||||
like ($output, qr/4 four/, 'task 4');
|
||||
unlike ($output, qr/one.+\d{1,2}\/\d{1,2}\/\d{4} foo1/ms, 'first annotation task 1');
|
||||
unlike ($output, qr/foo1.+\d{1,2}\/\d{1,2}\/\d{4} foo2/ms, 'second annotation task 1');
|
||||
like ($output, qr/one.+\d{1,2}\/\d{1,2}\/\d{4} foo3/ms, 'third annotation task 1');
|
||||
unlike ($output, qr/two.+\d{1,2}\/\d{1,2}\/\d{4} bar1/ms, 'first annotation task 2');
|
||||
like ($output, qr/two.+\d{1,2}\/\d{1,2}\/\d{4} bar2/ms, 'second annotation task 2');
|
||||
like ($output, qr/three.+\d{1,2}\/\d{1,2}\/\d{4} baz1/ms, 'third annotation task 3');
|
||||
like ($output, qr/4 tasks/, 'count');
|
||||
|
||||
$output = qx{../task rc:annotate.rc rc.annotation.details:0 rrr};
|
||||
like ($output, qr/1 \+one/, 'task 1');
|
||||
like ($output, qr/2 \+two/, 'task 2');
|
||||
like ($output, qr/3 \+three/, 'task 3');
|
||||
like ($output, qr/4 four/, 'task 4');
|
||||
unlike ($output, qr/one.+\d{1,2}\/\d{1,2}\/\d{4} foo1/ms, 'first annotation task 1');
|
||||
unlike ($output, qr/foo1.+\d{1,2}\/\d{1,2}\/\d{4} foo2/ms, 'second annotation task 1');
|
||||
unlike ($output, qr/foo2.+\d{1,2}\/\d{1,2}\/\d{4} foo3/ms, 'third annotation task 1');
|
||||
unlike ($output, qr/two.+\d{1,2}\/\d{1,2}\/\d{4} bar1/ms, 'first annotation task 2');
|
||||
unlike ($output, qr/bar1.+\d{1,2}\/\d{1,2}\/\d{4} bar2/ms, 'second annotation task 2');
|
||||
unlike ($output, qr/three.+\d{1,2}\/\d{1,2}\/\d{4} baz1/ms, 'third annotation task 3');
|
||||
like ($output, qr/4 tasks/, 'count');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
|
|
|
@ -155,8 +155,8 @@ int main (int argc, char** argv)
|
|||
t.ok (good, "Att::mod (noword)");
|
||||
|
||||
good = true;
|
||||
try {a6.mod ("fartwizzle");} catch (...) {good = false;}
|
||||
t.notok (good, "Att::mod (fartwizzle)");
|
||||
try {a6.mod ("unrecognized");} catch (...) {good = false;}
|
||||
t.notok (good, "Att::mod (unrecognized)");
|
||||
|
||||
// Att::parse
|
||||
Nibbler n ("");
|
||||
|
|
|
@ -33,7 +33,8 @@ use Test::More tests => 7;
|
|||
# Create the rc file.
|
||||
if (open my $fh, '>', 'basic.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
print $fh "data.location=.\n",
|
||||
"default.command=\n";
|
||||
close $fh;
|
||||
ok (-r 'basic.rc', 'Created basic.rc');
|
||||
}
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2010, Paul Beckingham.
|
||||
## All rights reserved.
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify it under
|
||||
## the terms of the GNU General Public License as published by the Free Software
|
||||
## Foundation; either version 2 of the License, or (at your option) any later
|
||||
## version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
## details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License along with
|
||||
## this program; if not, write to the
|
||||
##
|
||||
## Free Software Foundation, Inc.,
|
||||
## 51 Franklin Street, Fifth Floor,
|
||||
## Boston, MA
|
||||
## 02110-1301
|
||||
## USA
|
||||
##
|
||||
################################################################################
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 6;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'duplicate.rc')
|
||||
{
|
||||
print $fh "data.location=.\n",
|
||||
"data.location=.\n",
|
||||
"color=off\n";
|
||||
close $fh;
|
||||
ok (-r 'duplicate.rc', 'Created duplicate.rc');
|
||||
}
|
||||
|
||||
# Test the add command.
|
||||
my $output = qx{../task rc:duplicate.rc config};
|
||||
like ($output, qr/data\.location/ms, 'Duplicate entry detected');
|
||||
unlike ($output, qr/colorl/ms, 'Single entry not ignored');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'undo.data';
|
||||
ok (!-r 'undo.data', 'Removed undo.data');
|
||||
|
||||
unlink 'duplicate.rc';
|
||||
ok (!-r 'duplicate.rc', 'Removed duplicate.rc');
|
||||
|
||||
exit 0;
|
||||
|
|
@ -33,69 +33,47 @@ Context context;
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
UnitTest t (18);
|
||||
UnitTest t (11);
|
||||
|
||||
// void set (const std::string&, const int);
|
||||
// int get (const std::string&, const int);
|
||||
Config c;
|
||||
c.set ("int1", 0);
|
||||
t.is (c.get ("int1", 9), 0, "Config::set/get int");
|
||||
|
||||
c.set ("int2", 3);
|
||||
t.is (c.get ("int2", 9), 3, "Config::set/get int");
|
||||
|
||||
c.set ("int3", -9);
|
||||
t.is (c.get ("int3", 9), -9, "Config::set/get int");
|
||||
|
||||
// void set (const std::string&, const double);
|
||||
// double get (const std::string&, const double);
|
||||
c.set ("double1", 0.0);
|
||||
t.is (c.get ("double1", 9.0), 0.0, "Config::set/get double");
|
||||
|
||||
c.set ("double2", 3.0);
|
||||
t.is (c.get ("double2", 9.0), 3.0, "Config::set/get double");
|
||||
|
||||
c.set ("double3", -9.0);
|
||||
t.is (c.get ("double3", 9.0), -9.0, "Config::set/get double");
|
||||
|
||||
// void set (const std::string&, const std::string&);
|
||||
c.set ("str1", "one");
|
||||
t.is (c.get ("str1", ""), "one", "Config::set/get std::string");
|
||||
|
||||
c.set ("str1", "");
|
||||
t.is (c.get ("str1", "no"), "", "Config::set/get std::string");
|
||||
|
||||
// const std::string get (const char*);
|
||||
c.set ("str1", "one");
|
||||
t.is (c.get ((char*) "str1"), (char*)"one", "Config::set/get char*");
|
||||
|
||||
// const std::string get (const char*, const char*);
|
||||
c.set ("str1", "one");
|
||||
t.is (c.get ((char*)"str1", (char*)""), "one", "Config::set/get char*");
|
||||
|
||||
c.set ("str1", "");
|
||||
t.is (c.get ((char*)"str1", (char*)"no"), "", "Config::set/get char*");
|
||||
|
||||
// const std::string get (const std::string&);
|
||||
c.set ("str1", "one");
|
||||
t.is (c.get (std::string ("str1")), "one", "Config::set/get std::string");
|
||||
t.is (c.get ("str1"), "one", "Config::set/get std::string");
|
||||
|
||||
c.set ("str1", "");
|
||||
t.is (c.get (std::string ("str1")), "", "Config::set/get std::string");
|
||||
t.is (c.get ("str1"), "", "Config::set/get std::string");
|
||||
|
||||
// const std::string get (const std::string&, const std::string&);
|
||||
c.set ("str1", "one");
|
||||
t.is (c.get (std::string ("str1"), std::string ("no")), "one", "Config::set/get std::string");
|
||||
// void set (const std::string&, const int);
|
||||
// const int getInteger (const std::string&);
|
||||
c.set ("int1", 1);
|
||||
t.is (c.getInteger ("int1"), 1, "Config::set/get int");
|
||||
|
||||
c.set ("str1", "");
|
||||
t.is (c.get (std::string ("str1"), std::string ("no")), "", "Config::set/get std::string");
|
||||
c.set ("int2", 3);
|
||||
t.is (c.getInteger ("int2"), 3, "Config::set/get int");
|
||||
|
||||
// bool get (const std::string&, const bool);
|
||||
c.set ("int3", -9);
|
||||
t.is (c.getInteger ("int3"), -9, "Config::set/get int");
|
||||
|
||||
// void set (const std::string&, const double);
|
||||
// const double getReal (const std::string&);
|
||||
c.set ("double1", 1.0);
|
||||
t.is (c.getReal ("double1"), 1.0, "Config::set/get double");
|
||||
|
||||
c.set ("double2", 3.0);
|
||||
t.is (c.getReal ("double2"), 3.0, "Config::set/get double");
|
||||
|
||||
c.set ("double3", -9.0);
|
||||
t.is (c.getReal ("double3"), -9.0, "Config::set/get double");
|
||||
|
||||
// void set (const std::string&, const bool);
|
||||
// const bool getBoolean (const std::string&);
|
||||
c.set ("bool1", false);
|
||||
t.is (c.get (std::string ("bool1"), (bool)true), false, "Config::set/get bool");
|
||||
t.is (c.getBoolean ("bool1"), false, "Config::set/get bool");
|
||||
|
||||
c.set ("bool1", true);
|
||||
t.is (c.get (std::string ("bool1"), (bool)false), true, "Config::set/get bool");
|
||||
t.is (c.getBoolean ("bool1"), true, "Config::set/get bool");
|
||||
|
||||
// void all (std::vector <std::string>&);
|
||||
std::vector <std::string> all;
|
||||
|
|
|
@ -34,7 +34,7 @@ Context context;
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
UnitTest t (102);
|
||||
UnitTest t (111);
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -180,6 +180,21 @@ int main (int argc, char** argv)
|
|||
t.is (fromString7.day (), 1, "ctor (std::string) -> d");
|
||||
t.is (fromString7.year (), 2008, "ctor (std::string) -> y");
|
||||
|
||||
Date fromString8 ("Tue 01 Jan 2008 (01)", "a D b Y (V)");
|
||||
t.is (fromString8.month (), 1, "ctor (std::string) -> m");
|
||||
t.is (fromString8.day (), 1, "ctor (std::string) -> d");
|
||||
t.is (fromString8.year (), 2008, "ctor (std::string) -> y");
|
||||
|
||||
Date fromString9 ("Tuesday, January 1, 2008", "A, B d, Y");
|
||||
t.is (fromString9.month (), 1, "ctor (std::string) -> m");
|
||||
t.is (fromString9.day (), 1, "ctor (std::string) -> d");
|
||||
t.is (fromString9.year (), 2008, "ctor (std::string) -> y");
|
||||
|
||||
Date fromString10 ("v01 Tue 2008-01-01", "vV a Y-M-D");
|
||||
t.is (fromString10.month (), 1, "ctor (std::string) -> m");
|
||||
t.is (fromString10.day (), 1, "ctor (std::string) -> d");
|
||||
t.is (fromString10.year (), 2008, "ctor (std::string) -> y");
|
||||
|
||||
// Relative dates.
|
||||
Date r1 ("today");
|
||||
t.ok (r1.sameDay (now), "today = now");
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 9;
|
||||
use Test::More tests => 14;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'date1.rc')
|
||||
|
@ -47,6 +47,16 @@ if (open my $fh, '>', 'date2.rc')
|
|||
ok (-r 'date2.rc', 'Created date2.rc');
|
||||
}
|
||||
|
||||
if (open my $fh, '>', 'date3.rc')
|
||||
{
|
||||
print $fh "data.location=.\n",
|
||||
"dateformat=m/d/y\n",
|
||||
"weekstart=Monday\n",
|
||||
"reportdateformat=A D B Y (vV)\n";
|
||||
close $fh;
|
||||
ok (-r 'date3.rc', 'Created date3.rc');
|
||||
}
|
||||
|
||||
qx{../task rc:date1.rc add foo due:20091231};
|
||||
my $output = qx{../task rc:date1.rc info 1};
|
||||
like ($output, qr/\b20091231\b/, 'date format YMD parsed');
|
||||
|
@ -58,6 +68,15 @@ qx{../task rc:date2.rc add foo due:12/1/09};
|
|||
$output = qx{../task rc:date2.rc info 1};
|
||||
like ($output, qr/\b12\/1\/09\b/, 'date format m/d/y parsed');
|
||||
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
qx{../task rc:date3.rc add foo due:4/8/10};
|
||||
$output = qx{../task rc:date3.rc list};
|
||||
like ($output, qr/Thursday 08 April 2010 \(v14\)/, 'date format A D B Y (vV) parsed');
|
||||
$output = qx{../task rc:date3.rc rc.reportdateformat:"D b Y - a" list};
|
||||
like ($output, qr/08 Apr 2010 - Thu/, 'date format D b Y - a parsed');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
@ -71,5 +90,8 @@ ok (!-r 'date1.rc', 'Removed date1.rc');
|
|||
unlink 'date2.rc';
|
||||
ok (!-r 'date2.rc', 'Removed date2.rc');
|
||||
|
||||
unlink 'date3.rc';
|
||||
ok (!-r 'date3.rc', 'Removed date3.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ use Test::More tests => 17;
|
|||
if (open my $fh, '>', 'delete.rc')
|
||||
{
|
||||
print $fh "data.location=.\n",
|
||||
"confirmation=no\n",
|
||||
"echo.command=no\n";
|
||||
close $fh;
|
||||
ok (-r 'delete.rc', 'Created delete.rc');
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <algorithm>
|
||||
#include <Context.h>
|
||||
#include <Directory.h>
|
||||
#include <test.h>
|
||||
|
@ -33,7 +34,7 @@ Context context;
|
|||
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
UnitTest t (20);
|
||||
UnitTest t (21);
|
||||
|
||||
// Directory (const File&);
|
||||
// Directory (const Path&);
|
||||
|
@ -55,6 +56,9 @@ int main (int argc, char** argv)
|
|||
Directory d5 = d4;
|
||||
t.is (d5.data, "/tmp/test_directory", "Directory::operator=");
|
||||
|
||||
// operator (std::string) const;
|
||||
t.is ((std::string) d3, "/tmp", "Directory::operator (std::string) const");
|
||||
|
||||
// virtual bool create ();
|
||||
t.ok (d5.create (), "Directory::create /tmp/test_directory");
|
||||
t.ok (d5.exists (), "Directory::exists /tmp/test_directory");
|
||||
|
@ -67,12 +71,14 @@ int main (int argc, char** argv)
|
|||
|
||||
// std::vector <std::string> list ();
|
||||
std::vector <std::string> files = d5.list ();
|
||||
std::sort (files.begin (), files.end ());
|
||||
t.is ((int)files.size (), 2, "Directory::list 1 file");
|
||||
t.is (files[0], "/tmp/test_directory/dir", "file[0] is /tmp/test_directory/dir");
|
||||
t.is (files[1], "/tmp/test_directory/f0", "file[1] is /tmp/test_directory/f0");
|
||||
|
||||
// std::vector <std::string> listRecursive ();
|
||||
files = d5.listRecursive ();
|
||||
std::sort (files.begin (), files.end ());
|
||||
t.is ((int)files.size (), 2, "Directory::list 1 file");
|
||||
t.is (files[0], "/tmp/test_directory/dir/f1", "file is /tmp/test_directory/dir/f1");
|
||||
t.is (files[1], "/tmp/test_directory/f0", "file is /tmp/test_directory/f0");
|
||||
|
|
|
@ -33,7 +33,7 @@ Context context;
|
|||
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
UnitTest t (5);
|
||||
UnitTest t (6);
|
||||
|
||||
File::write ("/tmp/file.t.txt", "This is a test\n");
|
||||
File f6 ("/tmp/file.t.txt");
|
||||
|
@ -41,6 +41,9 @@ int main (int argc, char** argv)
|
|||
t.ok (f6.mode () & S_IRUSR, "File::mode /tmp/file.t.txt good");
|
||||
t.ok (File::remove ("/tmp/file.t.txt"), "File::remove /tmp/file.t.txt good");
|
||||
|
||||
// operator (std::string) const;
|
||||
t.is ((std::string) f6, "/tmp/file.t.txt", "File::operator (std::string) const");
|
||||
|
||||
t.ok (File::create ("/tmp/file.t.create"), "File::create /tmp/file.t.create good");
|
||||
t.ok (File::remove ("/tmp/file.t.create"), "File::remove /tmp/file.t.create good");
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// task - a command line task list manager.
|
||||
//
|
||||
// Copyright 2006 - 2009, Paul Beckingham.
|
||||
// Copyright 2006 - 2010, Paul Beckingham.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify it under
|
||||
|
@ -33,7 +33,7 @@ Context context;
|
|||
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
UnitTest t (26);
|
||||
UnitTest t (32);
|
||||
|
||||
// Path ();
|
||||
Path p0;
|
||||
|
@ -54,6 +54,9 @@ int main (int argc, char** argv)
|
|||
Path p3_copy (p3);
|
||||
t.is (p3.data, p3_copy.data, "Path::Path (Path&)");
|
||||
|
||||
// operator (std::string) const;
|
||||
t.is ((std::string) p3, "/tmp", "Path::operator (std::string) const");
|
||||
|
||||
// std::string name () const;
|
||||
Path p4 ("/a/b/c/file.ext");
|
||||
t.is (p4.name (), "file.ext", "/a/b/c/file.ext name is file.ext");
|
||||
|
@ -101,6 +104,13 @@ int main (int argc, char** argv)
|
|||
t.ok (out.size () == 1, "/[s-u]mp -> 1 result");
|
||||
t.is (out[0], "/tmp", "/[s-u]mp -> /tmp");
|
||||
|
||||
// bool is_absolute () const;
|
||||
t.notok (p0.is_absolute (), "'' !is_absolute");
|
||||
t.notok (p1.is_absolute (), "foo !is_absolute");
|
||||
t.ok (p2.is_absolute (), "~ is_absolute (after expansion)");
|
||||
t.ok (p3.is_absolute (), "/tmp is_absolute");
|
||||
t.ok (p4.is_absolute (), "/a/b/c/file.ext is_absolute");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
use strict;
|
||||
use warnings;
|
||||
use File::Path;
|
||||
use Test::More tests => 8;
|
||||
use Test::More tests => 12;
|
||||
|
||||
# Create the rc file, using rc.name:value.
|
||||
unlink 'foo.rc';
|
||||
|
@ -51,6 +51,23 @@ qx{echo 'y'|../task rc:foo.rc rc.data.location:foo};
|
|||
ok (-r 'foo.rc', 'Created default rc file');
|
||||
ok (-d 'foo', 'Created default data directory');
|
||||
|
||||
# Add a setting.
|
||||
qx{echo 'y'|../task rc:foo.rc config must_be_unique old};
|
||||
my $output = qx{../task rc:foo.rc config};
|
||||
like ($output, qr/^must_be_unique\s+old$/ms, 'config setting a new value');
|
||||
|
||||
qx{echo 'y'|../task rc:foo.rc config must_be_unique new};
|
||||
$output = qx{../task rc:foo.rc config};
|
||||
like ($output, qr/^must_be_unique\s+new$/ms, 'config overwriting an existing value');
|
||||
|
||||
qx{echo 'y'|../task rc:foo.rc config must_be_unique ''};
|
||||
$output = qx{../task rc:foo.rc config};
|
||||
like ($output, qr/^must_be_unique$/ms, 'config setting a blank value');
|
||||
|
||||
qx{echo 'y'|../task rc:foo.rc config must_be_unique};
|
||||
$output = qx{../task rc:foo.rc config};
|
||||
unlike ($output, qr/^must_be_unique/ms, 'config removing a value');
|
||||
|
||||
rmtree 'foo', 0, 0;
|
||||
ok (!-r 'foo', 'Removed foo');
|
||||
|
||||
|
|
|
@ -33,7 +33,8 @@ use Test::More tests => 28;
|
|||
# Create the rc file.
|
||||
if (open my $fh, '>', 'seq.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
print $fh "data.location=.\n",
|
||||
"confirmation=off\n";
|
||||
close $fh;
|
||||
ok (-r 'seq.rc', 'Created seq.rc');
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ use Test::More tests => 22;
|
|||
if (open my $fh, '>', 'shadow.rc')
|
||||
{
|
||||
print $fh "data.location=.\n",
|
||||
"confirmation=off\n",
|
||||
"shadow.file=./shadow.txt\n",
|
||||
"shadow.command=rc:shadow.rc stats\n",
|
||||
"shadow.notify=on\n";
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <unistd.h>
|
||||
#include <Context.h>
|
||||
#include <StringTable.h>
|
||||
#include <File.h>
|
||||
#include <util.h>
|
||||
#include <test.h>
|
||||
|
||||
|
@ -39,7 +40,7 @@ int main (int argc, char** argv)
|
|||
|
||||
// Create a string file.
|
||||
std::string file = "./strings.xx-XX";
|
||||
spit (file, "# comment\n1 found");
|
||||
File::write (file, "# comment\n1 found");
|
||||
t.is (access (file.c_str (), F_OK), 0, "strings.xx-XX created.");
|
||||
|
||||
// Load the string file.
|
||||
|
|
|
@ -34,7 +34,7 @@ Context context;
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
UnitTest t (439);
|
||||
UnitTest t (430);
|
||||
|
||||
// TODO bool confirm (const std::string&);
|
||||
// TODO int confirm3 (const std::string&);
|
||||
|
@ -514,23 +514,6 @@ int main (int argc, char** argv)
|
|||
|
||||
// TODO const std::string uuid ();
|
||||
|
||||
// std::string expandPath (const std::string&);
|
||||
t.ok (expandPath ("foo") == "foo", "expandPath nop");
|
||||
t.ok (expandPath ("~/") != "~/", "expandPath ~/");
|
||||
t.ok (expandPath ("~") != "~", "expandPath ~");
|
||||
|
||||
// bool isAbsolutePath (const std::string&);
|
||||
t.notok (isAbsolutePath ("."), "isAbsolutePath .");
|
||||
t.notok (isAbsolutePath ("~"), "isAbsolutePath ~");
|
||||
t.ok (isAbsolutePath (expandPath ("~")), "isAbsolutePath (expandPath ~)");
|
||||
t.ok (isAbsolutePath (expandPath ("~/")), "isAbsolutePath (expandPath ~/)");
|
||||
t.ok (isAbsolutePath ("/"), "isAbsolutePath /");
|
||||
t.ok (isAbsolutePath ("/tmp"), "isAbsolutePath /tmp");
|
||||
|
||||
// TODO bool slurp (const std::string&, std::vector <std::string>&, bool trimLines = false);
|
||||
// TODO bool slurp (const std::string&, std::string&, bool trimLines = false);
|
||||
// TODO void spit (const std::string&, const std::string&);
|
||||
|
||||
// std::string taskDiff (const Task&, const Task&);
|
||||
Task left;
|
||||
left.set ("zero", "0");
|
||||
|
|
|
@ -352,7 +352,7 @@ std::string ucFirst (const std::string& input)
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
const char* optionalBlankLine ()
|
||||
{
|
||||
if (context.config.get ("blanklines", true) == true) // no i18n
|
||||
if (context.config.getBoolean ("blanklines") == true) // no i18n
|
||||
return newline;
|
||||
|
||||
return noline;
|
||||
|
|
131
src/util.cpp
131
src/util.cpp
|
@ -341,49 +341,6 @@ const std::string uuid ()
|
|||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// no i18n
|
||||
std::string expandPath (const std::string& in)
|
||||
{
|
||||
std::string copy = in;
|
||||
std::string::size_type tilde;
|
||||
|
||||
if ((tilde = copy.find ("~/")) != std::string::npos)
|
||||
{
|
||||
struct passwd* pw = getpwuid (getuid ());
|
||||
copy.replace (tilde, 1, pw->pw_dir);
|
||||
}
|
||||
else if ((tilde = copy.find ("~")) != std::string::npos)
|
||||
{
|
||||
struct passwd* pw = getpwuid (getuid ());
|
||||
std::string home = pw->pw_dir;
|
||||
home += "/";
|
||||
copy.replace (tilde, 1, home);
|
||||
}
|
||||
else if ((tilde = copy.find ("~")) != std::string::npos)
|
||||
{
|
||||
std::string::size_type slash;
|
||||
if ((slash = copy.find ("/", tilde)) != std::string::npos)
|
||||
{
|
||||
std::string name = copy.substr (tilde + 1, slash - tilde - 1);
|
||||
struct passwd* pw = getpwnam (name.c_str ());
|
||||
if (pw)
|
||||
copy.replace (tilde, slash - tilde, pw->pw_dir);
|
||||
}
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool isAbsolutePath (const std::string& in)
|
||||
{
|
||||
if (in.length () && in[0] == '/')
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// On Solaris no flock function exists.
|
||||
#ifdef SOLARIS
|
||||
|
@ -418,92 +375,6 @@ int flock (int fd, int operation)
|
|||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool slurp (
|
||||
const std::string& file,
|
||||
std::vector <std::string>& contents,
|
||||
bool trimLines /* = false */)
|
||||
{
|
||||
contents.clear ();
|
||||
|
||||
std::ifstream in (file.c_str ());
|
||||
if (in.good ())
|
||||
{
|
||||
std::string line;
|
||||
while (getline (in, line))
|
||||
{
|
||||
if (trimLines) line = trim (line);
|
||||
contents.push_back (line);
|
||||
}
|
||||
|
||||
in.close ();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool slurp (
|
||||
const std::string& file,
|
||||
std::string& contents,
|
||||
bool trimLines /* = false */)
|
||||
{
|
||||
contents = "";
|
||||
|
||||
std::ifstream in (file.c_str ());
|
||||
if (in.good ())
|
||||
{
|
||||
std::string line;
|
||||
while (getline (in, line))
|
||||
{
|
||||
if (trimLines) line = trim (line);
|
||||
contents += line + "\n";
|
||||
}
|
||||
|
||||
in.close ();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void spit (const std::string& file, const std::string& contents)
|
||||
{
|
||||
std::ofstream out (file.c_str ());
|
||||
if (out.good ())
|
||||
{
|
||||
out << contents;
|
||||
out.close ();
|
||||
}
|
||||
else
|
||||
throw std::string ("Could not write file '") + file + "'"; // TODO i18n
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void spit (
|
||||
const std::string& file,
|
||||
const std::vector <std::string>& lines,
|
||||
bool addNewlines /* = true */)
|
||||
{
|
||||
std::ofstream out (file.c_str ());
|
||||
if (out.good ())
|
||||
{
|
||||
foreach (line, lines)
|
||||
{
|
||||
out << *line;
|
||||
|
||||
if (addNewlines)
|
||||
out << "\n";
|
||||
}
|
||||
|
||||
out.close ();
|
||||
}
|
||||
else
|
||||
throw std::string ("Could not write file '") + file + "'"; // TODO i18n
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool taskDiff (const Task& before, const Task& after)
|
||||
{
|
||||
|
@ -589,7 +460,7 @@ std::string renderAttribute (const std::string& name, const std::string& value)
|
|||
if (a.type (name) == "date")
|
||||
{
|
||||
Date d ((time_t)::atoi (value.c_str ()));
|
||||
return d.toString (context.config.get ("dateformat", "m/d/Y"));
|
||||
return d.toString (context.config.get ("dateformat"));
|
||||
}
|
||||
|
||||
return value;
|
||||
|
|
|
@ -60,8 +60,6 @@ std::string formatSecondsCompact (time_t);
|
|||
std::string formatBytes (size_t);
|
||||
int autoComplete (const std::string&, const std::vector<std::string>&, std::vector<std::string>&);
|
||||
const std::string uuid ();
|
||||
std::string expandPath (const std::string&);
|
||||
bool isAbsolutePath (const std::string&);
|
||||
|
||||
#ifdef SOLARIS
|
||||
#define LOCK_SH 1
|
||||
|
@ -72,10 +70,6 @@ bool isAbsolutePath (const std::string&);
|
|||
int flock (int, int);
|
||||
#endif
|
||||
|
||||
bool slurp (const std::string&, std::vector <std::string>&, bool trimLines = false);
|
||||
bool slurp (const std::string&, std::string&, bool trimLines = false);
|
||||
void spit (const std::string&, const std::string&);
|
||||
void spit (const std::string&, const std::vector <std::string>&, bool addNewlines = true);
|
||||
bool taskDiff (const Task&, const Task&);
|
||||
std::string taskDifferences (const Task&, const Task&);
|
||||
std::string renderAttribute (const std::string&, const std::string&);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue