Compare commits

..

104 Commits

Author SHA1 Message Date
Gina Trapani
294051fe5c Birdseye: Update version and changelog 2016-03-17 20:34:07 -04:00
Gina Trapani
5c6e3a36c1 Birdseye: Tabs to spaces 2016-03-17 20:34:02 -04:00
Gina Trapani
d32b5d62ad Birdseye: whitespace 2016-03-17 20:33:55 -04:00
Gina Trapani
def2a4b7c6 Merge pull request #153 from JonathanReeve/addons
Update birdseye script for compatibility with Python 3
2016-03-17 20:20:08 -04:00
Jonathan Reeve
732e45aeb1 remove unnecessary apostrophes 2015-02-15 14:54:50 -05:00
Jonathan Reeve
a53bb81b4c update for python 3 2015-02-15 14:53:02 -05:00
Jonathan Reeve
29a470f97d make scripts executable 2015-02-15 14:41:26 -05:00
Gina Trapani
6ab0004fe8 Fix IndexError: list index out of range when there's a blank line in todo.txt (like after deleting a task) 2012-02-14 18:02:11 -08:00
bertvv
15acb054f5 Have birdseye plugin use instead of hard-coded directory 2011-07-07 23:45:48 -07:00
ginatrapani
5f3dadee5c Updated to latest in master 2009-04-26 10:04:49 -07:00
Gina Trapani
20c6f44784 Ported README to Textile 2009-04-12 02:43:57 -04:00
Gina Trapani
9bab224a29 Merge branch 'master' of git://github.com/ginatrapani/todo.txt-cli into addons
* 'master' of git://github.com/ginatrapani/todo.txt-cli:
  Bugfix: pri accepted priorities of more than a single letter
  Don't set sort command in default todo.cfg.
  Don't set colors in default todo.cfg.
  Cleanup: removing annoying trailing space on pri tasks
  Cleanup: del/depri/pri: some more $2 -> $item
  Bugfix: handling of priorities in pri/depri/do: no more globbing
  Bugfix, take 2: depri no longer wipes out entire task with other parens http://tech.groups.yahoo.com/group/todotxt/message/1828
  Bugfix: depri no longer wipes out entire task with other parens http://tech.groups.yahoo.com/group/todotxt/message/1828
  Fix misplaced quote that was blocking filename globbing in the action
  Add quotes around $action to handle cases where todo.actions.d path includes embedded spaces.
2009-04-12 02:41:57 -04:00
Philippe Teuwen
4d3b7472ff Bugfix: pri accepted priorities of more than a single letter
e.g. todo.sh pri 1 aa

Signed-off-by: Gina Trapani <ginatrapani@gmail.com>
2009-04-11 08:20:15 +08:00
Emil Sit
680e93e737 Don't set sort command in default todo.cfg.
Instead of directly setting a value in todo.cfg, let the user
know what the default is and how to customize it.  This allows
developers the flexibility of changing the default in todo.sh
without having to worry about fixing people's config files.

Signed-off-by: Emil Sit <sit@emilsit.net>
2009-04-07 20:34:10 -04:00
Emil Sit
477738828f Don't set colors in default todo.cfg.
Users are probably unlikely to change the definition
of colors like $BLACK so just define them in todo.sh
and comment them out in todo.cfg.  Similarly, leave
default values for priority coloring available but
commented out.

Signed-off-by: Emil Sit <sit@emilsit.net>
2009-04-07 20:34:10 -04:00
Philippe Teuwen
b9f95633dc Cleanup: removing annoying trailing space on pri tasks
Signed-off-by: Gina Trapani <ginatrapani@gmail.com>
2009-04-08 07:44:41 +08:00
Philippe Teuwen
df1e2eb7cf Cleanup: del/depri/pri: some more $2 -> $item
Signed-off-by: Gina Trapani <ginatrapani@gmail.com>
2009-04-08 07:36:20 +08:00
Philippe Teuwen
a4e68f9c3f Bugfix: handling of priorities in pri/depri/do: no more globbing
Signed-off-by: Gina Trapani <ginatrapani@gmail.com>
2009-04-08 07:36:02 +08:00
Gina Trapani
3028de42a8 Bugfix, take 2: depri no longer wipes out entire task with other parens http://tech.groups.yahoo.com/group/todotxt/message/1828 2009-04-07 10:32:16 -07:00
Gina Trapani
8fceae171d Bugfix: depri no longer wipes out entire task with other parens http://tech.groups.yahoo.com/group/todotxt/message/1828 2009-04-07 10:24:06 -07:00
Dave Hein
9898e7df3f Fix misplaced quote that was blocking filename globbing in the action
'usage' logic.

Signed-off-by: Gina Trapani <ginatrapani@gmail.com>
2009-04-08 00:12:08 +08:00
Dave Hein
42e1a658d6 Add quotes around $action to handle cases where todo.actions.d path includes embedded spaces.
There were a couple places where $action was used without quotes
that caused a problem if the .todo.actions.d had a parent directory
path that included spaces (e.g. /cygdrive/c/Documents\ and\ Settings/jo-user).
This was in the section that calls the addons with the 'usage' arg.

Signed-off-by: Gina Trapani <ginatrapani@gmail.com>
2009-04-08 00:11:49 +08:00
Gina Trapani
a075adb4ec Merge git://github.com/ginatrapani/todo.txt-cli into addons 2009-04-06 12:37:31 -07:00
Philippe Teuwen
f1caecec4e TODO_ACTIONS_D is now TODO_ACTIONS_DIR
Signed-off-by: Gina Trapani <ginatrapani@gmail.com>
2009-04-07 03:34:33 +08:00
Philippe Teuwen
078c69496f Parametrize .todo.actions.d location
Signed-off-by: Gina Trapani <ginatrapani@gmail.com>
2009-04-07 03:34:01 +08:00
Gina Trapani
01a250c702 Added symlink support, tweaked usage message 2009-04-05 18:52:42 -07:00
Gina Trapani
1f17672215 Added birdseye add-on 2009-04-05 18:08:38 -07:00
Gina Trapani
40e0da5108 more info 2009-04-05 11:45:57 -07:00
Gina Trapani
56dfae0486 first commit 2009-04-05 11:42:16 -07:00
Gina Trapani
8549eef46b first commit 2009-04-05 11:21:12 -07:00
Gina Trapani
8567a90e4c Bugfix: Replace echoes old todo before new todo. 2009-04-05 10:49:06 -07:00
Philippe Teuwen
55f45e8515 tests: first unset TODOTXT_CFG_FILE
Signed-off-by: Gina Trapani <ginatrapani@gmail.com>
2009-04-05 06:37:38 +08:00
Gina
03ccc73703 Added missing file required for tests 2009-04-04 14:49:30 -07:00
U-STARBUCK\gina
a822560d44 Added user-facing download link 2009-04-04 12:21:53 -07:00
U-STARBUCK\gina
d860c2c36e Converted tab to spaces 2009-04-04 12:18:57 -07:00
U-STARBUCK\gina
7f954d73ae Merged test and dist Makefile to master branch for easier dev 2009-04-04 12:16:18 -07:00
U-STARBUCK\gina
8e864568a9 Allow custom sort (tx edgewood) 2009-04-02 22:47:50 -07:00
Emil Sit
df4f9150cf Remove gawk and uniq dependencies for listcon, listproj.
Implement listcon and listproj in terms of grep -w -o, which prints
words that match the given regular expression, and sort -u, which
obviates uniq.  This probably only works with GNU grep, which seems
better than having to rely on gawk (which is used nowhere else).

Signed-off-by: Emil Sit <sit@emilsit.net>

Signed-off-by: Gina Trapani <ginatrapani@gmail.com>
2009-04-03 13:32:20 +08:00
Emil Sit
5cc988102d Misc. whitespace cleanups.
Single space after colon.
No end-of-line whitespace.
Replace tabs with whitespace.

Signed-off-by: Emil Sit <sit@emilsit.net>

Signed-off-by: Gina Trapani <ginatrapani@gmail.com>
2009-04-03 13:32:20 +08:00
U-STARBUCK\gina
3a0fd43270 Moving Makefile dist infrastructure to a separate branch 2009-04-02 21:49:12 -07:00
U-STARBUCK\gina
1a6ff81e28 Makefile infrastructure 2009-04-02 21:01:44 -07:00
Emil Sit
5491e458a2 tests: Simple null test of all list commands
Signed-off-by: Emil Sit <sit@emilsit.net>
2009-04-02 21:09:35 -04:00
Emil Sit
5789f5b4c2 Convenience Makefile for running tests inside tests dir.
Simply call up to parent directory where all the real rules
are specified.

Signed-off-by: Emil Sit <sit@emilsit.net>
2009-04-02 21:09:19 -04:00
Emil Sit
b17cb11ec6 Initial test framework and first test.
Add a basic test framework, borrowed from the framework used
by git.git.  A shell script library (tests/test-lib.sh) helps
generate the fixtures, and simplifies the process of writing
test scripts.  Tests can be run as a suite (via 'make test')
or individually (sh tests/t0000-config.sh).  Results are aggregated
upon completion.  Includes a detailed README.

A basic test of config file processing is part of this commit.

Signed-off-by: Emil Sit <sit@emilsit.net>
2009-04-02 21:09:10 -04:00
Emil Sit
0b3d9109de todo.sh: Generate version info at dist time.
When generating the distribution files, prepare todo.sh
by subbing in the current version so that users will
get a proper version number.

Tries to detect VERSION-FILE for running from
the development directory but this doesn't work well
when $PWD is not the top of the git repo.

Signed-off-by: Emil Sit <sit@emilsit.net>
2009-04-02 21:05:58 -04:00
Emil Sit
ad40ef0f18 Basic Makefile and infrastructure to support dist tarballs.
Borrowing slightly from git.git, derive a VERSION-FILE
from the current state of user's git working directory.
The VERSION is derived relative to the latest git annotated
tag object (using git-describe) and includable either in
shell scripts or in Makefiles.

The basic 'make dist' target generates a .tar.gz and a .zip
file named by the detected version.

Also include a basic clean target and dummy test target.

Signed-off-by: Emil Sit <sit@emilsit.net>
2009-04-02 21:05:58 -04:00
Emil Sit
31216fe365 _list: Fix line/item counting, accounting for blank lines.
If a file had blank lines or was totally empty, _list would
result in an in-correct count of total items (either "" or
the number of lines, instead of the number of items).  This
commit splits the filtering into three phases: line numbering,
filtering (optional), and post-processing, and then does
counting separately, if desired.

Signed-off-by: Emil Sit <sit@emilsit.net>

Signed-off-by: Gina Trapani <ginatrapani@gmail.com>
2009-04-03 07:42:43 +08:00
Emil Sit
7f5c8fb3e1 Add a short help message to be called for -h.
Put the old help message under a "help" command.  The
short help message just lists the available commands and
should fit on a single screen.

Signed-off-by: Gina Trapani <ginatrapani@gmail.com>
2009-03-21 07:20:35 +08:00
Emil Sit
3e7b60abcd Factor out common usage message text.
Signed-off-by: Gina Trapani <ginatrapani@gmail.com>
2009-03-21 07:20:29 +08:00
Emil Sit
cc3e5f73aa _list: Add in an extra filter to remove empty lines.
The rewrite of ls functionality may have allowed blank but numbered
lines to creep into the ls display.  Search for such lines and
exclude them.

Signed-off-by: Emil Sit <sit@emilsit.net>

Signed-off-by: Gina Trapani <ginatrapani@gmail.com>
2009-03-21 07:20:28 +08:00
Gina Trapani
52604ebf78 Tweaked version and contributor details 2009-03-19 18:52:47 -07:00
Gina Trapani
bbe153b9bb Merge branch 'harding/master' 2009-03-19 18:40:10 -07:00
Gina Trapani
ec54a032cb Removed edit action 2009-03-19 18:37:36 -07:00
David A. Harding
758cdc5551 Merge branch 'gina/master' 2009-03-19 07:10:09 -04:00
David A. Harding
02dc030225 Putting Quotes Around $TODO_TMP
Suggested by Gina.
2009-03-19 07:06:07 -04:00
David A. Harding
7b769b2eea s/[A-Z]/[[:upper:]]/ 2009-03-17 19:15:27 -04:00
David A. Harding
39ee9ab045 Added -vv For Debugging Output 2009-03-17 14:07:48 -04:00
Gina Trapani
1e5902d0e2 Merge branch 'master' of git@github.com:ginatrapani/todo.txt-cli 2009-03-16 12:28:34 -05:00
Matt Brubeck
3df7497287 Add TODOTXT_DEFAULT_ACTION variable.
I like to set this to "ls" so I can just run "todo.sh" (or "t") to list my
tasks.

Signed-off-by: Gina Trapani <ginatrapani@gmail.com>
2009-03-17 01:04:20 +08:00
David A. Harding
07bb979d43 Move Filter Command Up & Remove Extra Sort Command 2009-03-14 15:06:53 -04:00
Ed Blackman
7e04849a4f Move filter before priority text changes, so filter doesn't match invisible text 2009-03-14 13:39:27 -04:00
David A. Harding
f8b2646b92 Don't Echo Empty Lines & Streamline Sed wc -l Syntax 2009-03-14 09:35:10 -04:00
Ed Blackman
02980ae7ee Fix "post_hilter_command" typo 2009-03-14 01:18:42 -04:00
Ed Blackman
12bbf8fe67 Fix spacing (tabs to spaces) 2009-03-14 01:17:46 -04:00
Ed Blackman
ab78607506 Use sed line counting to replace 'wc -l' 2009-03-14 01:15:52 -04:00
David A. Harding
6be78ca5fa Added Exclusion Syntax by Jacobo de Vera
-keyword or -"key phrase" should exclude those terms from the output.
2009-03-13 22:21:48 -04:00
Ed Blackman
9ab77253db Implement pre and post filters in _list 2009-03-13 18:17:16 -04:00
Ed Blackman
cf3c5312bf Export _list for call by extensions 2009-03-13 17:02:31 -04:00
Ed Blackman
37a7bb0e8a Use relative rather than absolute filename in status message 2009-03-13 16:40:55 -04:00
Ed Blackman
ed8e8e24d9 Consistent spacing for \ continuation in _list 2009-03-13 16:34:25 -04:00
David A. Harding
d6f00ca42f Minor formatting and comments changes 2009-03-13 12:14:08 -04:00
David A. Harding
a03a3bf66b Fixed Windows Regression, New _list Function
Commit f55f5e8b5f introduced a known regression on Windows that
prevented users from using configuration files starting with C:\.  The
following logic fixes this:
    +    ## If the file starts with a "/" use absolute path. Otherwise,
    +    ## try to find it in either $TODO_DIR or using a relative path
    +    if [ "${1:0:1}" == / ]
    +    then
    +        ## Absolute path
    +        src="$FILE"
    +    elif [ -f "$TODO_DIR/$FILE" ]
    +    then
    +        ## Path relative to todo.sh directory
    +        src="$TODO_DIR/$1"
    +    elif [ -f "$FILE" ]
    +    then
    +       ## Path relative to current working directory
    +       src="$FILE"
    +    else
    +        echo "TODO: File $FILE does not exist."
    +       exit 1
    +    fi

New _list function takes a filename and a list of search expressions.
We no longer use exec to call ourselves recursively.
2009-03-13 11:59:03 -04:00
David A. Harding
448cecb91d Simplify and Reused Code to Print ls Summary Line 2009-03-13 11:00:34 -04:00
David A. Harding
ee59233c36 Replaced Grep Loop, Fixed Sed Bug, Some Small Changes
Implemented several suggestions by Jacobo de Vera:

    > 1. [lines 539-551]: [...] replace the for loop with simply this:
    >    PADDING=${#LINES}

    > 2. [line 558]: As the script now supports a 6 digit number of tasks,
    > the first substitution should add 5 spaces instead of 2

    > 3. [lines 606-613]: The first search item is processed before the for
    >    loop, and the loop does the same for the rest. Wouldn't making this
    >    more general make the code more readable?

The changes for suggestion #3 let me add a new feature: when VERBOSE is
enabled, the summary line prints more info -- and it prints it on every
run:

    $ todo.sh ls "buy a"
    34 Buy a portable gas can @errands +safe
    --
    TODO: 1 of 49 tasks shown from /home/harding/var/git/todo/todo.txt

Also, generalizing and centralizing the code added a small but
measurable speed increase.

No new known regressions were introduced.
2009-03-12 22:23:59 -04:00
David A. Harding
f55f5e8b5f Make ls-Family Actions Use Listfile Backend
Essentially,

    ls)
	shift
	exec "$TODO_SH" listfile "$TODO_FILE" "$@"
	;;
    lsa)
	shift
	cat "$TODO_FILE" "$DONE_FILE" > "$TMP_FILE"
	exec $TODO_SH listfile "$TMP_FILE" "$@"
	;;
    lsp)
	shift ## was "listpri"
	shift ## was priority
	exec $TODO_SH listfile "$TODO_FILE" "$pri" "$@"
	;;;

Also adds the following features:

    1. Numbers are padded with up to five zeros (but only the minimum
       necessary), letting you list up to 999,999 tasks with the same
       formatting.

    2. All ls-family commands hide context, priority, and project when
       the user sets those hide options.

    3. Quoted arguments are passed on to grep as whole arguments,
       enabling the following:

	$ todo.sh ls buy a | head -n2
	34 Buy a portable gas can
	22 Buy door

	$ todo.sh ls "buy a"
	34 Buy a portable gas can

    4. listfile can take an absolute path. Any filename starting with a
       "/" will be treated as an absolute path; any other filename will
       be treated as relative to $TODO_DIR. Since a leading "/" would be
       striped by the operating system anyway under the old code, this
       is fully backward compatible.

Contains the following regressions:

    1. The ls verbose line count messages are more generic.

    2. There is no verbose line count line for lspri.

    3. I don't think listfile's absolute path feature will work on
       Windows. If it doesn't, either this patch needs to be thrown
       away, listall needs to be rewritten, or (my preference) $TMP_FILE
       needs to set as relative to $TODO_DIR.
2009-03-12 11:52:28 -04:00
David A. Harding
d508ed9dee Modularized Listing Sed
Still more to do tomorrow.
2009-03-12 01:02:10 -04:00
Matt Brubeck
62f3313ff9 Merge branch 'master' of git://github.com/ginatrapani/todo.txt-cli 2009-03-11 16:22:27 -07:00
David A. Harding
6bc374c5f2 Revert "Set ls As the Default Action"
This reverts commit 87959a8aa8.
2009-03-11 17:54:25 -04:00
David A. Harding
87959a8aa8 Set ls As the Default Action
.
Suggested by mbrubeck
2009-03-11 17:42:15 -04:00
Matt Brubeck
3e9d40ebd7 'edit' plugin to open files in a text editor. 2009-03-11 11:36:23 -07:00
Matt Brubeck
6bc05000d9 Add TODOTXT_DEFAULT_ACTION variable.
I like to set this to "ls" so I can just run "todo.sh" (or "t") to list my
tasks.
2009-03-11 10:50:14 -07:00
David A. Harding
717f052f13 Only Reset Action When Necessary plus Comments 2009-03-09 16:19:30 -04:00
Philippe Teuwen
4ee8c332ed Remove redundant code 2009-03-09 20:43:42 +01:00
David A. Harding
88caf44e9e Override Overrides Using "command"
New action, "command", forces todo.sh to use builtins and ignore any
.todo.actions.d scripts.  For example, if there is an executable
.todo.actions.d/ls:

    ## Run .todo.actions.d/ls
    todo.sh ls

    ## Run builtin todo.sh ls
    todo.sh command ls

This mimicks bash's behaviour:

    ## Use the default echo
    harding@ziggy:~$ echo 'foo\nbar'
    foo\nbar

    ## Alias the echo command to "echo -e"
    harding@ziggy:~$ alias echo='echo -e'
    harding@ziggy:~$ echo 'foo\nbar'
    foo
    bar

    ## Force bash to call the default echo command
    harding@ziggy:~$ command echo 'foo\nbar'
    foo\nbar
2009-03-09 14:10:21 -04:00
Philippe Teuwen
db66767170 Add TODOTXT_UNDEF_CUSTOM_ACTIONS for recursive call of todo.sh from actions
And replace tabs by spaces.

To illustrate the interest of this new variable, here is an action
to replace the original add to allow a priority to be set when adding.
The action itself relies on the original add, therefore the need for
this new envvar.

action=$1
shift
[ "$action" = "usage" ] && {
  echo "    add pri PRIORITY \"THING I NEED TO DO +project @context\""
  echo "      add an item and prioritize it in one step"
  echo ""
  exit
}

. $TODOTXT_CFG_FILE
TODOTXT_UNDEF_CUSTOM_ACTIONS=1
PRIORITY=false
if [ x"$1" = x"pri" -o x"$1" = x"p" ] && [[ x"$2" =~ x[a-zA-Z] ]]; then
    PRIORITY=$2
    shift
    shift
fi
if $TODO_SH add "$@" && [ $PRIORITY != false ]; then
    # figure out the line of what we just added, and "do" it
    line=`wc -l "$TODO_FILE" | cut -d' ' -f1`
    $TODO_SH pri "$line" $PRIORITY
fi
2009-03-09 10:09:32 +01:00
David A. Harding
f8f8e83c40 Merge branch 'gina/master'
Conflicts:

	todo.sh
2009-03-08 22:29:27 -04:00
Philippe Teuwen
2648bb047c Keep it simple
Signed-off-by: Gina Trapani <ginatrapani@gmail.com>
2009-03-09 08:58:32 +08:00
Philippe Teuwen
bbff2d13bb Remove usage call and export TODOTXT_SH for action.d
Signed-off-by: Gina Trapani <ginatrapani@gmail.com>
2009-03-09 08:55:28 +08:00
David A. Harding
e4c7979888 Merge branch 'gina/master'
Conflicts:

	todo.sh
2009-03-08 20:50:27 -04:00
Ed Blackman
47c7ba75b3 Remove now-redundant export of CFG_FILE 2009-03-08 18:41:27 -04:00
Philippe Teuwen
2bd2e9f7bd Options & environment variables: add namespace & allow for preset
This patch does 2 things:
- Allowing environment variables corresponding to options (e.g. VERBOSE for -v)
to be predefined in the user environment instead of having to always use
the corresponding option.
- Adding namespace TODOTXT_ to those envvars to avoid clashes in user environment

todo.action.d scripts can call recursively todo.sh and this patch preserves
the options/envvars through the calls.
As a bonus, now the user can export in advance one of those variables in
his/her environment and it would have the same effect as using the todo.sh
corresponding option.

export TODOTXT_AUTO_ARCHIVE=0          is same as option -a
export TODOTXT_CFG_FILE=CONFIG_FILE    is same as option -d CONFIG_FILE
export TODOTXT_FORCE=1                 is same as option -f
export TODOTXT_PRESERVE_LINE_NUMBERS=0 is same as option -n
export TODOTXT_PLAIN=1                 is same as option -p
export TODOTXT_DATE_ON_ADD=1           is same as option -t
export TODOTXT_VERBOSE=1               is same as option -v

Signed-off-by: Gina Trapani <ginatrapani@gmail.com>
2009-03-09 06:28:52 +08:00
U-STARBUCK\gina
f37cedc7ca Removed index.html 2009-03-08 14:47:33 -07:00
David A. Harding
7b2c9f080a Merged In Gina's Latest 2009-03-08 12:08:04 -04:00
David A. Harding
98646a575a Exit If .todo.actions.d Script Is Run
.
Suggested by Philippe Teuwen, this patch undoes a lot of the unnecessary
formating changes in my previous patch.
2009-03-08 11:46:26 -04:00
David A. Harding
e6649e6293 Removed Extended Regexes from Hiding Code
.
Dave Hein noticed the extended regular expressions (regex) in the
original patch don't work by default on Mac OS X (FreeBSD sed).  Now
using his suggested regex format: [[:space:]]@[^[:space:]]\{1,\}
.
Also changed: I misapplied part of the patch originally.  That's now
fixed.  I expanded part of the regular expression in the list
sub-expression so that I could change part of the coloring code.
2009-03-08 11:25:12 -04:00
U-STARBUCK\gina
eb61752708 Merge branch 'gh-pages' of git://github.com/ginatrapani/todo.txt-cli 2009-03-07 21:51:54 -08:00
Ed Blackman
5683490c0e Export variables so that they can be easily used in actions
Signed-off-by: Gina Trapani <ginatrapani@gmail.com>
2009-03-08 09:53:41 +08:00
David A. Harding
20e6892775 Run .todo.actions.d Before Builtins
.
Let users override default commands by creating a script in
~/.todo.actions.d/ with the same name as a default command.  Idea by Don
Harper and David A. Harding; patch by Harding.
.
The patch adds the following logic and increases the indent level for
the case statement:
.
+if [ -d "$HOME/.todo.actions.d" -a -x "$HOME/.todo.actions.d/$action" ]
+then
+    CFG_FILE="$CFG_FILE" "$HOME/.todo.actions.d/$action" "$@"
+else
+    case $action in
2009-03-07 16:15:15 -05:00
David A. Harding
fd9b002ce1 Hiding Priority, Context, and Project
.
Adds three new switches that hide priorty, context, and project text in
list output.
.
Changes proposed by Dave Hein.  Original patch by Dave Hein.  Revised
patch by David A. Harding. Thread starts at
http://tech.groups.yahoo.com/group/todotxt/message/1848
2009-03-07 13:05:40 -05:00
atduskgreg
7736e6b4fa Added a note to the README to point to Gina's branch.
Signed-off-by: ginatrapani <ginatrapani@gmail.com>
2009-03-07 06:30:27 +08:00
Philippe Teuwen
586abe8282 Cleaning indentation and mix of tabs/spaces, nothing else I swear ;-)
Signed-off-by: ginatrapani <ginatrapani@gmail.com>
2009-03-07 06:00:08 +08:00
U-STARBUCK\gina
25c6505007 Shortened README 2009-03-05 17:56:56 -08:00
U-STARBUCK\gina
9c6efe2ed7 Version 2.1 first commit 2009-03-05 17:26:24 -08:00
U-STARBUCK\gina
7ecda8973b first commit 2009-03-05 17:18:07 -08:00
32 changed files with 2221 additions and 1665 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
VERSION-FILE
tests/test-results
tests/trash\ directory.*

10
.todo.actions.d/README Normal file
View File

@@ -0,0 +1,10 @@
TODO.TXT CLI Add-ons
adda (symlink to aa for fewer keystrokes)
* Adds a task and prioritizes it A in one shot
addx (symlink ax for fewer keystrokes)
* Adds a task and marks it as complete in one shot
birdseye (requires Python in path and birdseye.py file)
* Generates a textual report of open and complete tasks in all contexts and projects

20
.todo.actions.d/adda Executable file
View File

@@ -0,0 +1,20 @@
#!/bin/bash
action=$1
shift
[ "$action" = "usage" ] && {
echo " Add and prioritize A:"
curcmd=`basename $0`
echo " $curcmd \"THING I NEED TO DO +project @context\""
echo " Add an item and prioritize it A in one step"
echo ""
exit
}
if "$TODO_SH" command add "$@"; then
# figure out the line of what we just added, and prioritize it A
line=`sed -n '$ =' "$TODO_FILE"`
echo "$line"
"$TODO_SH" command pri "$line" A
fi

20
.todo.actions.d/addx Executable file
View File

@@ -0,0 +1,20 @@
#!/bin/bash
action=$1
shift
[ "$action" = "usage" ] && {
echo " Add and do:"
curcmd=`basename $0`
echo " $curcmd \"THING I DID +project @context\""
echo " Add an item and mark it as done in one step"
echo ""
exit
}
if "$TODO_SH" command add "$@"; then
# figure out the line of what we just added, and prioritize it A
line=`sed -n '$ =' "$TODO_FILE"`
echo "$line"
"$TODO_SH" command do "$line"
fi

16
.todo.actions.d/birdseye Executable file
View File

@@ -0,0 +1,16 @@
#!/bin/bash
action=$1
shift
[ "$action" = "usage" ] && {
echo " Bird's eye report:"
echo " birdseye"
echo " generates a textual report of pending and completed tasks in all projects and contexts"
echo ""
exit
}
[ "$action" = "birdseye" ] && {
python ${TODO_ACTIONS_DIR}/birdseye.py "$TODO_FILE" "$DONE_FILE"
}

202
.todo.actions.d/birdseye.py Executable file
View File

@@ -0,0 +1,202 @@
#!/usr/bin/python
""" TODO.TXT Bird's Eye View Reporter
USAGE:
birdseye.py [todo.txt] [done.txt]
USAGE NOTES:
Expects two text files as parameters, each of which formatted as follows:
- One todo per line, ie, "call Mom"
- with an optional project association indicated as such: "+projectname"
- with the context in which the tasks should be completed, indicated as such: "@context"
- with the task priority optionally listed at the front of the line, in parens, ie, "(A)"
For example, 4 lines of todo.txt might look like this:
+garagesale @phone schedule Goodwill pickup
(A) @phone Tell Mom I love her
+writing draft Great American Novel
(B) smell the roses
The done.txt file is a list of completed todos from todo.txt.
See more on todo.txt here:
http://todotxt.com
OUTPUT:
Displays a list of:
- working projects and their percentage complete
- contexts in which open todos exist
- contexts and projects with tasks that have been prioritized
- projects which are completely done (don't have any open todos)
CHANGELOG:
2016.03.17 - Update for Python 3. Tx, JonathanReeve!
2006.07.29 - Now supports p:, p- and + project notation. Tx, Pedro!
2006.05.02 - Released
"""
import sys
__version__ = "1.2"
__date__ = "2006/05/02"
__updated__ = "2016/03/17"
__author__ = "Gina Trapani (ginatrapani@gmail.com)"
__copyright__ = "Copyright 2006 - 2016, Gina Trapani"
__license__ = "GPL"
__history__ = """
1.2 - Update for Python 3. Tx, JonathanReeve!
1.1 - Now supports p:, p- and + project notation. Tx, Pedro!
1.0 - Released.
"""
def usage():
print("USAGE: %s [todo.txt] [done.txt]" % (sys.argv[0], ))
def printTaskGroups(title, taskDict, priorityList, percentages):
print("")
print("%s"% (title,))
separator("-")
if not taskDict:
print("No items to list.")
else:
# sort the dictionary by value
# http://python.fyxm.net/peps/pep-0265.html
items = [(v, k) for k, v in list(taskDict.items())]
items.sort()
items.reverse() # so largest is first
items = [(k, v) for v, k in items]
for item in items:
if item[0] in priorityList:
if item[0] not in percentages:
printTaskGroup(item, -1, "*")
else:
printTaskGroup(item, percentages[item[0]], "*")
for item in items:
if item[0] not in priorityList:
if item[0] not in percentages:
printTaskGroup(item, -1, " ")
else:
printTaskGroup(item, percentages[item[0]], " ")
def printTaskGroup(p, pctage, star):
if pctage > -1:
progressBar = ""
numStars = int(pctage//10)
progressBar = "=" * numStars
numSpaces = 10 - numStars
for n in range(numSpaces):
progressBar += " "
if pctage > 9:
displayTotal = " %d%%"% (pctage, );
else:
displayTotal = " %d%%"% (pctage, );
print("%s %s [%s] %s (%d todos)"% (star, displayTotal, progressBar, p[0], p[1],))
else:
print("%s %s (%d todos)"% (star, p[0], p[1], ))
def separator(c):
sep = ""
sep = c * 42
print(sep)
def main(argv):
# make sure you have all your args
if len(argv) < 2:
usage()
sys.exit(2)
# process todo.txt
try:
f = open (argv[0], "r")
projects = {}
contexts = {}
projectPriority = []
contextPriority = []
for line in f:
prioritized = False
words = line.split()
if words and words[0].startswith("("):
prioritized = True
for word in words:
if word[0:2] == "p:" or word[0:2] == "p-" or word[0:1] == "+":
if word not in projects:
projects[word] = 1
else:
projects[word] = projects.setdefault(word,0) + 1
if prioritized:
projectPriority.append(word)
if word[0:1] == "@":
if word not in contexts:
contexts[word] = 1
else:
contexts[word] = contexts.setdefault(word, 0) + 1
if prioritized:
contextPriority.append(word)
f.close()
except IOError:
print("ERROR: The file named %s could not be read."% (argv[0], ))
usage()
sys.exit(2)
# process done.txt
try:
completedTasks = {}
f = open (argv[1], "r")
for line in f:
words = line.split()
for word in words:
if word[0:2] == "p:" or word[0:2] == "p-" or word[0:1] == "+":
if word not in completedTasks:
completedTasks[word] = 1
else:
completedTasks[word] = completedTasks.setdefault(word, 0) + 1
f.close()
except IOError:
print("ERROR: The file named %s could not be read."% (argv[1], ))
usage()
sys.exit(2)
# calculate percentages
projectPercentages = {}
for project in projects:
openTasks = projects[project]
if project in completedTasks:
closedTasks = completedTasks[project]
else:
closedTasks = 0
totalTasks = openTasks + closedTasks
projectPercentages[project] = (closedTasks*100) / totalTasks
# get projects all done
projectsWithNoIncompletes = {}
for task in completedTasks:
if task not in projects:
projectsWithNoIncompletes[task] = 0
# print out useful info
#print "TODO.TXT Bird's Eye View Report %s"% ( datetime.date.today().isoformat(), )
print("")
print("TODO.TXT Bird's Eye View Report")
separator("=")
printTaskGroups("Projects with Open TODOs", projects, projectPriority, projectPercentages)
printTaskGroups("Contexts with Open TODOs", contexts, contextPriority, projectPercentages)
printTaskGroups("Completed Projects (No open TODOs)", projectsWithNoIncompletes, projectPriority, projectPercentages)
print("")
print("* Projects and contexts with an asterisk next to them denote prioritized tasks.")
print("Project with prioritized tasks are listed first, then sorted by number of open todos.")
print("")
if __name__ == "__main__":
main(sys.argv[1:])

38
GEN-VERSION-FILE Executable file
View File

@@ -0,0 +1,38 @@
#!/bin/sh
# Based on git's GIT-VERSION-GEN.
VF=VERSION-FILE
DEF_VER=v2.2
LF='
'
if test -d .git -o -f .git &&
VN=$(git describe --abbrev=4 HEAD 2>/dev/null) &&
case "$VN" in
*$LF*) (exit 1) ;;
v[0-9]*)
git update-index -q --refresh
test -z "$(git diff-index --name-only HEAD --)" ||
VN="$VN-dirty" ;;
esac
then
VN=$(echo "$VN" | sed -e 's/-/./g');
else
VN="$DEF_VER"
fi
VN=$(expr "$VN" : v*'\(.*\)')
if test -r $VF
then
VC=$(sed -e 's/^VERSION=//' <$VF)
else
VC=unset
fi
test "$VN" = "$VC" || {
echo >&2 "VERSION=$VN"
echo "VERSION=$VN" >$VF
}

52
Makefile Normal file
View File

@@ -0,0 +1,52 @@
#
# Makefile for todo.txt
#
# Dynamically detect/generate version file as necessary
# This file will define a variable called VERSION.
.PHONY: .FORCE-VERSION-FILE
VERSION-FILE: .FORCE-VERSION-FILE
@./GEN-VERSION-FILE
-include VERSION-FILE
# Maybe this will include the version in it.
todo.sh: VERSION-FILE
# For packaging
DISTFILES := todo.cfg
DISTNAME=todo.txt_cli-$(VERSION)
dist: $(DISTFILES) todo.sh
mkdir -p $(DISTNAME)
cp -f $(DISTFILES) $(DISTNAME)/
sed -e 's/@DEV_VERSION@/'$(VERSION)'/' todo.sh > $(DISTNAME)/todo.sh
tar cf $(DISTNAME).tar $(DISTNAME)/
gzip -f -9 $(DISTNAME).tar
zip -9r $(DISTNAME).zip $(DISTNAME)/
rm -r $(DISTNAME)
.PHONY: clean
clean:
rm -f $(DISTNAME).tar.gz $(DISTNAME).zip
#
# Testing
#
TESTS = $(wildcard tests/t[0-9][0-9][0-9][0-9]-*.sh)
#TEST_OPTIONS=--verbose
test-pre-clean:
rm -rf tests/test-results "tests/trash directory"*
aggregate-results: $(TESTS)
$(TESTS): test-pre-clean
-cd tests && sh $(notdir $@) $(TEST_OPTIONS)
test: aggregate-results
tests/aggregate-results.sh tests/test-results/t*-*
rm -rf tests/test-results
# Force tests to get run every time
.PHONY: test test-pre-clean aggregate-results $(TESTS)

26
README.textile Normal file
View File

@@ -0,0 +1,26 @@
h1. TODO.TXT Command Line Interface
A simple and extensible shell script for managing your todo.txt file.
h2. "Downloads":http://github.com/ginatrapani/todo.txt-cli/downloads
"Download the latest stable release":http://github.com/ginatrapani/todo.txt-cli/downloads for use on your desktop or server.
h2. "Documentation":http://wiki.github.com/ginatrapani/todo.txt-cli
* "User Documentation":http://wiki.github.com/ginatrapani/todo.txt-cli/user-documentation - Find out "how to install and use Todo.txt CLI":http://wiki.github.com/ginatrapani/todo.txt-cli/user-documentation, and get tips and tricks.
* "Developer Documentation":http://wiki.github.com/ginatrapani/todo.txt-cli/developer-documentation - "Contribute to Todo.txt CLI":http://wiki.github.com/ginatrapani/todo.txt-cli/developer-documentation and build your own custom add-ons.
h2. "Mailing List":http://groups.yahoo.com/group/todotxt/
Get support from users and developers on the "mailing list":http://groups.yahoo.com/group/todotxt/.
h2. Quick Links
* Original anemic release by "Gina Trapani":http://ginatrapani.org on 5/11/2006.
* Raised to great heights by "brainy and dedicated volunteers":http://github.com/ginatrapani/todo.txt-cli/network.
* Licensed under the "GPL":http://www.gnu.org/copyleft/gpl.html
* "Add-on Directory":http://wiki.github.com/ginatrapani/todo.txt-cli/todosh-add-on-directory
* "Changelog":http://wiki.github.com/ginatrapani/todo.txt-cli/todosh-changelog
* "Known Bugs":http://wiki.github.com/ginatrapani/todo.txt-cli/known-bugs

View File

@@ -1,686 +0,0 @@
/*!
* Bootstrap Responsive v2.0.2
*
* Copyright 2012 Twitter, Inc
* Licensed under the Apache License v2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Designed and built with all the love in the world @twitter by @mdo and @fat.
*/
.clearfix {
*zoom: 1;
}
.clearfix:before,
.clearfix:after {
display: table;
content: "";
}
.clearfix:after {
clear: both;
}
.hide-text {
overflow: hidden;
text-indent: 100%;
white-space: nowrap;
}
.input-block-level {
display: block;
width: 100%;
min-height: 28px;
/* Make inputs at least the height of their button counterpart */
/* Makes inputs behave like true block-level elements */
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
}
.hidden {
display: none;
visibility: hidden;
}
.visible-phone {
display: none;
}
.visible-tablet {
display: none;
}
.visible-desktop {
display: block;
}
.hidden-phone {
display: block;
}
.hidden-tablet {
display: block;
}
.hidden-desktop {
display: none;
}
@media (max-width: 767px) {
.visible-phone {
display: block;
}
.hidden-phone {
display: none;
}
.hidden-desktop {
display: block;
}
.visible-desktop {
display: none;
}
}
@media (min-width: 768px) and (max-width: 979px) {
.visible-tablet {
display: block;
}
.hidden-tablet {
display: none;
}
.hidden-desktop {
display: block;
}
.visible-desktop {
display: none;
}
}
@media (max-width: 480px) {
.nav-collapse {
-webkit-transform: translate3d(0, 0, 0);
}
.page-header h1 small {
display: block;
line-height: 18px;
}
input[type="checkbox"],
input[type="radio"] {
border: 1px solid #ccc;
}
.form-horizontal .control-group > label {
float: none;
width: auto;
padding-top: 0;
text-align: left;
}
.form-horizontal .controls {
margin-left: 0;
}
.form-horizontal .control-list {
padding-top: 0;
}
.form-horizontal .form-actions {
padding-left: 10px;
padding-right: 10px;
}
.modal {
position: absolute;
top: 10px;
left: 10px;
right: 10px;
width: auto;
margin: 0;
}
.modal.fade.in {
top: auto;
}
.modal-header .close {
padding: 10px;
margin: -10px;
}
.carousel-caption {
position: static;
}
}
@media (max-width: 767px) {
body {
padding-left: 20px;
padding-right: 20px;
}
.navbar-fixed-top {
margin-left: -20px;
margin-right: -20px;
}
.container {
width: auto;
}
.row-fluid {
width: 100%;
}
.row {
margin-left: 0;
}
.row > [class*="span"],
.row-fluid > [class*="span"] {
float: none;
display: block;
width: auto;
margin: 0;
}
.thumbnails [class*="span"] {
width: auto;
}
input[class*="span"],
select[class*="span"],
textarea[class*="span"],
.uneditable-input {
display: block;
width: 100%;
min-height: 28px;
/* Make inputs at least the height of their button counterpart */
/* Makes inputs behave like true block-level elements */
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
}
.input-prepend input[class*="span"],
.input-append input[class*="span"] {
width: auto;
}
}
@media (min-width: 768px) and (max-width: 979px) {
.row {
margin-left: -20px;
*zoom: 1;
}
.row:before,
.row:after {
display: table;
content: "";
}
.row:after {
clear: both;
}
[class*="span"] {
float: left;
margin-left: 20px;
}
.container,
.navbar-fixed-top .container,
.navbar-fixed-bottom .container {
width: 724px;
}
.span12 {
width: 724px;
}
.span11 {
width: 662px;
}
.span10 {
width: 600px;
}
.span9 {
width: 538px;
}
.span8 {
width: 476px;
}
.span7 {
width: 414px;
}
.span6 {
width: 352px;
}
.span5 {
width: 290px;
}
.span4 {
width: 228px;
}
.span3 {
width: 166px;
}
.span2 {
width: 104px;
}
.span1 {
width: 42px;
}
.offset12 {
margin-left: 764px;
}
.offset11 {
margin-left: 702px;
}
.offset10 {
margin-left: 640px;
}
.offset9 {
margin-left: 578px;
}
.offset8 {
margin-left: 516px;
}
.offset7 {
margin-left: 454px;
}
.offset6 {
margin-left: 392px;
}
.offset5 {
margin-left: 330px;
}
.offset4 {
margin-left: 268px;
}
.offset3 {
margin-left: 206px;
}
.offset2 {
margin-left: 144px;
}
.offset1 {
margin-left: 82px;
}
.row-fluid {
width: 100%;
*zoom: 1;
}
.row-fluid:before,
.row-fluid:after {
display: table;
content: "";
}
.row-fluid:after {
clear: both;
}
.row-fluid > [class*="span"] {
float: left;
margin-left: 2.762430939%;
}
.row-fluid > [class*="span"]:first-child {
margin-left: 0;
}
.row-fluid > .span12 {
width: 99.999999993%;
}
.row-fluid > .span11 {
width: 91.436464082%;
}
.row-fluid > .span10 {
width: 82.87292817100001%;
}
.row-fluid > .span9 {
width: 74.30939226%;
}
.row-fluid > .span8 {
width: 65.74585634900001%;
}
.row-fluid > .span7 {
width: 57.182320438000005%;
}
.row-fluid > .span6 {
width: 48.618784527%;
}
.row-fluid > .span5 {
width: 40.055248616%;
}
.row-fluid > .span4 {
width: 31.491712705%;
}
.row-fluid > .span3 {
width: 22.928176794%;
}
.row-fluid > .span2 {
width: 14.364640883%;
}
.row-fluid > .span1 {
width: 5.801104972%;
}
input,
textarea,
.uneditable-input {
margin-left: 0;
}
input.span12, textarea.span12, .uneditable-input.span12 {
width: 714px;
}
input.span11, textarea.span11, .uneditable-input.span11 {
width: 652px;
}
input.span10, textarea.span10, .uneditable-input.span10 {
width: 590px;
}
input.span9, textarea.span9, .uneditable-input.span9 {
width: 528px;
}
input.span8, textarea.span8, .uneditable-input.span8 {
width: 466px;
}
input.span7, textarea.span7, .uneditable-input.span7 {
width: 404px;
}
input.span6, textarea.span6, .uneditable-input.span6 {
width: 342px;
}
input.span5, textarea.span5, .uneditable-input.span5 {
width: 280px;
}
input.span4, textarea.span4, .uneditable-input.span4 {
width: 218px;
}
input.span3, textarea.span3, .uneditable-input.span3 {
width: 156px;
}
input.span2, textarea.span2, .uneditable-input.span2 {
width: 94px;
}
input.span1, textarea.span1, .uneditable-input.span1 {
width: 32px;
}
}
@media (max-width: 979px) {
body {
padding-top: 0;
}
.navbar-fixed-top {
position: static;
margin-bottom: 18px;
}
.navbar-fixed-top .navbar-inner {
padding: 5px;
}
.navbar .container {
width: auto;
padding: 0;
}
.navbar .brand {
padding-left: 10px;
padding-right: 10px;
margin: 0 0 0 -5px;
}
.navbar .nav-collapse {
clear: left;
}
.navbar .nav {
float: none;
margin: 0 0 9px;
}
.navbar .nav > li {
float: none;
}
.navbar .nav > li > a {
margin-bottom: 2px;
}
.navbar .nav > .divider-vertical {
display: none;
}
.navbar .nav .nav-header {
color: #999999;
text-shadow: none;
}
.navbar .nav > li > a,
.navbar .dropdown-menu a {
padding: 6px 15px;
font-weight: bold;
color: #999999;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
.navbar .dropdown-menu li + li a {
margin-bottom: 2px;
}
.navbar .nav > li > a:hover,
.navbar .dropdown-menu a:hover {
background-color: #222222;
}
.navbar .dropdown-menu {
position: static;
top: auto;
left: auto;
float: none;
display: block;
max-width: none;
margin: 0 15px;
padding: 0;
background-color: transparent;
border: none;
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
.navbar .dropdown-menu:before,
.navbar .dropdown-menu:after {
display: none;
}
.navbar .dropdown-menu .divider {
display: none;
}
.navbar-form,
.navbar-search {
float: none;
padding: 9px 15px;
margin: 9px 0;
border-top: 1px solid #222222;
border-bottom: 1px solid #222222;
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
-moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
}
.navbar .nav.pull-right {
float: none;
margin-left: 0;
}
.navbar-static .navbar-inner {
padding-left: 10px;
padding-right: 10px;
}
.btn-navbar {
display: block;
}
.nav-collapse {
overflow: hidden;
height: 0;
}
}
@media (min-width: 980px) {
.nav-collapse.collapse {
height: auto !important;
overflow: visible !important;
}
}
@media (min-width: 1200px) {
.row {
margin-left: -30px;
*zoom: 1;
}
.row:before,
.row:after {
display: table;
content: "";
}
.row:after {
clear: both;
}
[class*="span"] {
float: left;
margin-left: 30px;
}
.container,
.navbar-fixed-top .container,
.navbar-fixed-bottom .container {
width: 1170px;
}
.span12 {
width: 1170px;
}
.span11 {
width: 1070px;
}
.span10 {
width: 970px;
}
.span9 {
width: 870px;
}
.span8 {
width: 770px;
}
.span7 {
width: 670px;
}
.span6 {
width: 570px;
}
.span5 {
width: 470px;
}
.span4 {
width: 370px;
}
.span3 {
width: 270px;
}
.span2 {
width: 170px;
}
.span1 {
width: 70px;
}
.offset12 {
margin-left: 1230px;
}
.offset11 {
margin-left: 1130px;
}
.offset10 {
margin-left: 1030px;
}
.offset9 {
margin-left: 930px;
}
.offset8 {
margin-left: 830px;
}
.offset7 {
margin-left: 730px;
}
.offset6 {
margin-left: 630px;
}
.offset5 {
margin-left: 530px;
}
.offset4 {
margin-left: 430px;
}
.offset3 {
margin-left: 330px;
}
.offset2 {
margin-left: 230px;
}
.offset1 {
margin-left: 130px;
}
.row-fluid {
width: 100%;
*zoom: 1;
}
.row-fluid:before,
.row-fluid:after {
display: table;
content: "";
}
.row-fluid:after {
clear: both;
}
.row-fluid > [class*="span"] {
float: left;
margin-left: 2.564102564%;
}
.row-fluid > [class*="span"]:first-child {
margin-left: 0;
}
.row-fluid > .span12 {
width: 100%;
}
.row-fluid > .span11 {
width: 91.45299145300001%;
}
.row-fluid > .span10 {
width: 82.905982906%;
}
.row-fluid > .span9 {
width: 74.358974359%;
}
.row-fluid > .span8 {
width: 65.81196581200001%;
}
.row-fluid > .span7 {
width: 57.264957265%;
}
.row-fluid > .span6 {
width: 48.717948718%;
}
.row-fluid > .span5 {
width: 40.170940171000005%;
}
.row-fluid > .span4 {
width: 31.623931624%;
}
.row-fluid > .span3 {
width: 23.076923077%;
}
.row-fluid > .span2 {
width: 14.529914530000001%;
}
.row-fluid > .span1 {
width: 5.982905983%;
}
input,
textarea,
.uneditable-input {
margin-left: 0;
}
input.span12, textarea.span12, .uneditable-input.span12 {
width: 1160px;
}
input.span11, textarea.span11, .uneditable-input.span11 {
width: 1060px;
}
input.span10, textarea.span10, .uneditable-input.span10 {
width: 960px;
}
input.span9, textarea.span9, .uneditable-input.span9 {
width: 860px;
}
input.span8, textarea.span8, .uneditable-input.span8 {
width: 760px;
}
input.span7, textarea.span7, .uneditable-input.span7 {
width: 660px;
}
input.span6, textarea.span6, .uneditable-input.span6 {
width: 560px;
}
input.span5, textarea.span5, .uneditable-input.span5 {
width: 460px;
}
input.span4, textarea.span4, .uneditable-input.span4 {
width: 360px;
}
input.span3, textarea.span3, .uneditable-input.span3 {
width: 260px;
}
input.span2, textarea.span2, .uneditable-input.span2 {
width: 160px;
}
input.span1, textarea.span1, .uneditable-input.span1 {
width: 60px;
}
.thumbnails {
margin-left: -30px;
}
.thumbnails > li {
margin-left: 30px;
}
}

584
css/bootstrap.min.css vendored

File diff suppressed because one or more lines are too long

View File

@@ -1,126 +0,0 @@
body {
padding-top:50px;
color:#777;
background:#666;
}
body, p, li, input, button, select, textarea {
font-family:;'Open Sans', sans-serif;
}
body, p, li {
font-size:14px;
line-height:20px;
}
h1, h2, h3 {letter-spacing: -1px;}
/* Links */
a {color:#18D;}
a:hover {color:#26B;}
/* Titles */
h1 {font-family:Courier;color: #196DB5;font-size:26px;font-weight:300;text-shadow: 0 1px -1px white;}
h1 a {color:white;}
h1 a:hover {color:white;text-decoration:none;}
h2 {color: #555;font-size:22px;font-weight:300;margin-bottom:10px;text-shadow: 0 1px -1px white;}
h3 {font-weight:normal;color:#444;margin-bottom: 10px;}
h4 {color: #444;margin-bottom: 2px;margin-top:10px;line-height:20px;}
h5 {color: #444;line-height:20px;}
h6 {line-height:20px; color:#AAA;}
.bold {font-weight:bold;}
.italic {font-style:italic;}
/* Hero unit */
.hero-unit {
background:#666;
border-bottom: 1px solid white;
-webkit-border-radius: 0;
-moz-border-radius:0;
border-radius: 0;
margin: 0;
margin-top:-50px;
padding:0;
}
.hero-unit .container {
padding: 40px 0 30px 0;
text-shadow:0 -1px 1px black;
}
.hero-unit h1{color:#E9E9E9;font-size:40px;margin-top:12px;letter-spacing:-2px;text-shadow: 0 -1px -1px black;}
.hero-unit h2, .hero-unit h4 {color:#fff;line-height:24px;text-shadow: 0 -1px -1px black;}
.hero-unit h1 > img {vertical-align:top;}
.hero-unit ul.unstyled li {border-bottom:1px solid #000;border-top:1px solid #2B2B2B;padding:15px 0 15px 15px;}
.hero-unit ul.unstyled li:first-child {border-top:0;}
.hero-unit ul.unstyled, .hero-unit hr {border-bottom:1px solid #2B2B2B;}
.hero-unit .buttons {
margin: 10px -15px 0 -15px;
padding:20px 0;
}
.hero-unit hr {border-top:1px solid #000;}
.hero-unit .buttons a, .hero-unit iframe {vertical-align:middle;}
.hero-unit .divider-vertical {
height:20px;
width:1px;
display:inline-block;
background-color:black;
border-right:1px solid #333;
vertical-align:middle;
margin:0 6px;
}
.hero-unit .github-btn-large .gh-btn, .hero-unit .github-btn-large .gh-count {
padding: 2px 10px 2px 8px !important;
font-size: 15px !important;
}
.hero-unit .btn-large {
padding: 3px 10px 3px 6px;
line-height: 22px;
}
.hero-unit .stitched {
outline: 1px dashed #444;
outline-offset: -5px;
background: #2B2B2B;
border-radius: 4px 4px 4px 4px;
-webkit-border-radius: 4px;
-moz-border-radius:4px;
}
/* Section */
.section {
background: white;
margin: -20px -20px 35px -20px;
padding:19px;
border:1px solid #DDD;
}
/*Footer*/
.footer {
background: #151515;
padding: 20px 10px 10px 10px;
box-shadow: inset 0 15px 10px rgba(0,0,0,0.6);
-webkit-box-shadow: inset 0 15px 10px rgba(0,0,0,0.6);
-moz-box-shadow:inset 0 15px 10px rgba(0,0,0,0.6);
color:#999;
}
.footer a {
color:#eee;
font-weight:normal;
}
/* Footer bottom */
.footer.footer-btm {
background:#151515;
border-top: 1px solid #222;
color:#999;
}
/* Responsive */
img {
max-width: 100%;
height: auto;
border: 0;
-ms-interpolation-mode: bicubic;
}
.above-footer {
background:#eee;
max-width:100%;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 KiB

View File

@@ -1,261 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Todo.txt: Future-proof task tracking in a file you control</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
<link rel="stylesheet" type="text/css" href="css/bootstrap-responsive.css"/>
<link rel="stylesheet" type="text/css" href="css/style.css"/>
<link href="http://fonts.googleapis.com/css?family=Open+Sans:400,600,700" rel="stylesheet" type="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Track your tasks and projects in a plain text file, todo.txt. A todo.txt is software and operating system agnostic; it's searchable, portable, lightweight and easily manipulated." />
<meta name="keywords" content="Todo.txt, To do list" />
<meta name="robots" content="all,follow" />
<meta name="author" content="Gina Trapani" />
<link rel="shortcut icon" href="favicon.png" />
</head>
<body id="body">
<div class="above-footer">
<div class="hero-unit">
<div class="container">
<div class="row">
<div class="span7">
<a href="" title="Todo.txt"><img src="images/todotxt_logo_2012.png" alt="Todo.txt" width="100" style="float:left;margin-right:10px"/></a>
<h1><a href="">Todo.txt</a></h1>
<h2>If you want to get it done, first write it down.</h2>
<br style="clear:both">
</div>
<span class="hidden-phone">
<div class="span3">
<a href="http://itunes.apple.com/us/app/todo.txt-touch/id491342186?ls=1&mt=8" title="Download on the App Store">
<img alt="Download on App Store" src="images/download-on-app-store.png" style="float:right"/>
</a>
</div>
<div class="span2">
<a href="http://play.google.com/store/apps/details?id=com.todotxt.todotxttouch" title="Get it on Google Play">
<img alt="Android app on Google Play" src="https://play.google.com/intl/en_us/badges/images/apps/en-play-badge-border.png" width="203" />
</a>
</div>
</span>
</div>
</div>
</div>
<div class="container content">
<div class="section">
<div class="row">
<div class="span12">
<span class="hidden-phone"><img src="images/todotxt-apps_lrg.png" alt="Todo.txt apps" width="768" style="float:right;margin-bottom:5px"/></span>
<h3>If you have a file called todo.txt on your computer right now, you're in the right place.</h3>
<p>So many power users try dozens of complicated todo list software applications, only to go right back to their trusty todo.txt file.</p>
<p>But it's not easy to open todo.txt, make a change, and save it—especially on your touchscreen device and at the command line. Todo.txt apps solve that problem.</p>
<h3>Simplicity is todo.txt's core value.</h3>
<p>You're not going to find many checkboxes, drop-downs, reminders, or date pickers here.</p>
<p>Todo.txt apps are minimal, todo.txt-focused editors which help you manage your tasks with as few keystrokes and taps possible.</p></div>
</div>
</div>
<div class="section">
<div class="row">
<div class="span4">
<h2>On Your Phone and Tablet</h2>
<span class="hidden-phone"><p><img src="images/mobileappsheader.png" alt="Todo.txt mobile apps" /></p></span>
<p>Your todo.txt file isn't useful if it's not always at your fingertips. The Todo.txt mobile apps make it easy to view and update your tasks on the go.</p>
<p>Currently connected to <a href="http://dropbox.com">Dropbox</a>, Todo.txt Touch helps you manage your todo.txt on your touchscreen mobile device and automatically syncs your changes to all your computers.</p>
<h4>iPhone, iPod touch, and iPad users:</h4>
<p>
<a href="http://itunes.apple.com/us/app/todo.txt-touch/id491342186?ls=1&mt=8" title="Download on the App Store">
<img alt="Download on App Store" src="images/download-on-app-store.png" />
</a>
</p>
<h4>Android users:</h4>
<p>
<a href="http://play.google.com/store/apps/details?id=com.todotxt.todotxttouch" title="Get it on Google Play">
<img alt="Android app on Google Play" src="https://play.google.com/intl/en_us/badges/images/apps/en-play-badge.png" width="203" />
</a>
</p>
<p>Also available in <a href="http://www.amazon.com/o/ASIN/B004MNQTVU/ref=nosim/lifehackerboo-20">the Amazon Appstore</a>.
</div>
<div class="span4">
<h2>At the Command Line</h2>
<p>With a simple but powerful shell script called todo.sh, you can interact with todo.txt at the command line for quick and easy, Unix-y access.</p>
<p><span class="hidden-phone"><iframe src="http://player.vimeo.com/video/3263629?byline=0&amp;portrait=0" width="100%" height="320" frameborder="0" webkitAllowFullScreen allowFullScreen></iframe></span></p>
<p>The Todo.txt CLI supports archiving completed tasks to done.txt and priority/context tab autocompletion.</p><br>
<p><a href="http://github.com/ginatrapani/todo.txt-cli/releases" class="btn-large btn-success" title="Download Todo.txt CLI">Download Todo.txt CLI &raquo;</a></p><br>
<p>Find out more:</p>
<p><ul>
<li><a href="http://wiki.github.com/ginatrapani/todo.txt-cli">Documentation</a>—everything you need to know about how to use Todo.txt CLI</li>
<li><a href="http://groups.yahoo.com/group/todotxt/">Mailing List</a>—ask the Todo.txt community</li>
</ul>
</p>
</div>
<div class="span4">
<h2>In Any Text Editor</h2>
<p>Countless productivity apps and sites store your tasks in their own proprietary database and file format. But you can work with your todo.txt file in every text editor ever made, regardless of operating system or vendor.</p>
<p>The todo.txt format is <a href="https://github.com/ginatrapani/todo.txt-cli/wiki/The-Todo.txt-Format">a simple set of rules</a> that make todo.txt both human and machine-readable. The format supports priorities, creation and completion dates, projects and contexts. That's all you need to be productive. <a href="todo.txt">See an example Todo.txt file</a>.</p><br>
<span class="hidden-tablet">
<h3>What Users Are Saying</h3>
<p>
<strong>The easiest to-do list I ever used.</strong> -<a href="https://play.google.com/store/apps/details?id=com.todotxt.todotxttouch&reviewId=bGc6QU9xcFRPR1UzN3RldEpIX05yTjhtQ0tyb3lEREd0SHhuY0RzaXVzU2FweVp2Z3JPQ2ZuNmNSMXltaWV2dHFCMk1HcUlRNDRJU0R1bTQ5dDJtMXBqMmow">Dennis</a>
<p>
<strong>Brilliant... the "cool" factor is off the charts.</strong> -<a href="https://play.google.com/store/apps/details?id=com.todotxt.todotxttouch&reviewId=bGc6QU9xcFRPSERJa1czRmcwaUtYT0lCa2RLZmlhWGlVZ1ppNGc1RWFzVERQT05paWZaRlBHMUZtRE0zQzJHVzhBRENiWEVHX3RrbGxMQ1ktcm1oSmFpazM0">John</a>
<p>
<strong>So simple, yet also very versatile and flexible. I love it!</strong> -<a href="https://play.google.com/store/apps/details?id=com.todotxt.todotxttouch&reviewId=bGc6QU9xcFRPR2p1QjdWRkZuUGdXN1hwYmNMTUJ5eGFoWDZPcTltemV5a1BkRWYwV3VSdGZ5WXhaWlA1WFNkajczS3dVa2dCRko1d2d1R1EwazdEZ0hXaGtn">mschooler93</a>
</p>
<p>
<strong>Extremely useful and well executed.</strong> -<a href="https://play.google.com/store/apps/details?id=com.todotxt.todotxttouch&reviewId=bGc6QU9xcFRPR1BpeV9OTXZsNE5wcXZKcWNMN1l1WWhROExia2dadkZNVjdqcGthSFhRQmZreEhVTEV3dENwRm1wSmQxc2dLT0FINUFHbWplem1EX01CLU13">nemof</a>
</p>
<p>
<strong>No frills, highly effective and convenient.</strong> -<a href="https://play.google.com/store/apps/details?id=com.todotxt.todotxttouch&reviewId=bGc6QU9xcFRPRUFjYkZRRG53RlBJYVNiYl83Vm5wbVZZOW5FQ01GQ2IyV2s5OFNCMDRwbFFac1NEUDJHeVVOSnFFWFpFVVJpaUVHZU1EXzR3elhwN2VtanJR">Will</a>
</p>
<br/><br/>
</span>
<h3>Developers</h3>
<p>Todo.txt CLI and Todo.txt Touch are proudly open source. Browse the source code for the <a href="https://github.com/ginatrapani/todo.txt-cli">CLI</a>, <a href="https://github.com/ginatrapani/todo.txt-touch-ios">iOS</a>, and <a href="https://github.com/ginatrapani/todo.txt-touch">Android</a>.</p>
</div>
</div>
</div>
<div class="section">
<div class="row">
<div class="span12">
<h2>Community Apps: Todo.txt on <em>your</em> favorite device or platform.</h2>
<p>In addition to the official Todo.txt apps, community members have built more apps and add-ons that work with Todo.txt.</p>
</div>
</div>
<div class="row">
<div class="span3">
<h3>Desktop</h3>
<h4><a href="http://benrhughes.com/todotxt.net/">Todotxt.net</a></h4>
<p>A minimalist, keyboard-driven Windows GUI for your todo.txt file, by <a href="http://benrhughes.com/">Ben Hughes</a>.</p>
<h4><a href="https://mjdescy.github.io/TodoTxtMac/">TodoTxtMac</a></h4>
<p>TodoTxtMac is a minimalist, keyboard-driven to-do manager for Mac OS X (10.8 Mountain Lion and higher), by <a href="https://github.com/mjdescy">mjdescy</a>.</p>
<h4><a href="http://nerdur.com/todour.html">Todour</a></h4>
<p>Todour is an application for handling todo.txt files on the Mac and Windows, by Sverrir Valgeirsson.</p>
<h4><a href="https://launchpad.net/~ximilian/+archive/ppa">DoStuff</a></h4>
<p>"A todo.txt client for humans" on Ubuntu (<a href="http://2buntu.com/1197/review-dostuff-a-todotxt-client-for-humans/">screenshots and video clip</a>), by ximilian.</p>
<h4><a href="http://burnsoftware.wordpress.com/daytasks/">DayTasks</a></h4>
<p>A fast, simple, and efficient todo.txt-compatible task list for Ubuntu, by Zach Burnham.</p>
<h4><a href="https://github.com/mNantern/QTodoTxt">QTodoTxt</a></h4>
<p>A fast, cross-platform todo.txt GUI written in Python, by Matthieu Nantern.</p>
<h4><a href="http://jdotxt.chschmid.com">jdotxt</a></h4>
<p>An open-source, Java-based client for Windows, Mac OS X and Linux, by Christian M. Schmid.</p>
<h4><a href="https://github.com/onovy/otodo">otodo</a></h4>
<p>Simple but powerfull TUI for todo.txt by Ondrej Novy.</p>
</div>
<div class="span3">
<h3>Web</h3>
<h4><a href="http://todotxttdi.com">Todotxttdi.com</a></h4>
<p>HTML5 Dropbox app with text-driven user interface (<a href="https://github.com/DavidPratten/todotxttdi">source</a>), by <a href="http://davidpratten.com">David Pratten</a>.</p>
<h4><a href="http://todo.martinsgill.co.uk">TodoTxtJs</a></h4>
<p>Interactive HTML5 todo.txt app with optional Dropbox integration (<a href="https://github.com/MartinSGill/TodoTxtJs">source</a>), by Martin Gill.</p>
<h4><a href="https://github.com/bicarbon8/todoTxtWebUi">todoTxtWebUi</a></h4>
<p>A web UI to use with a todo.txt file (<a href="http://monsoonstudios.com/Code/todoTxt/">demo</a>), by <a href="https://github.com/bicarbon8">Jason Holt</a>.</p>
<h4><a href="https://github.com/infews/bulldog">Bulldog</a></h4>
<p>HTML5 task manager, built on todo.txt, by <a href="https://github.com/infews">Davis W. Frank</a>.</p>
<h4><a href="https://github.com/trestletech/Todo.txt">Todo.txt++</a></h4>
<p>A sleek, hosted, mobile-friendly web app with Dropbox synchronization, filtering, and searching. You can use it <a href ="https://www.todotxtpp.com">here</a></p>
<h4><a href="https://chrome.google.com/webstore/detail/mndijfcodpjlhgjcpcbhncjakaboedbl">Todo.txt for Chrome</a></h4>
<p>Chrome extension with Dropbox integration, and features such as pending task count, saved filters, and more, by <a href="https://c306.net/">Aditya Bhaskar</a>.</p>
</div>
<div class="span3">
<h3>Plugins and Add-ons</h3>
<h4><a href="https://github.com/freitass/todo.txt-vim">Vim plugin for todo.txt</a></h4>
<p>by <a href="https://github.com/freitass">Leandro Freitas</a>.</p>
<h4><a href="https://ifttt.com/recipes/42299">#todo.txt IFTTT Recipe</a></h4>
<p>Add items to your todo.txt file in Dropbox from Google Chat, by Nick Barrett.</p>
<h4><a href="https://github.com/ginatrapani/todo.txt-cli/wiki/Todo.sh-Add-on-Directory">Todo.sh Add-on Directory</a></h4>
<p>A collection of add-ons, custom actions, and filters that enhance the Todo.txt CLI script, authored by community members.</p>
<h4><a href="https://github.com/dertuxmalwieder/SublimeTodoTxt">Sublime Text todo.txt syntax highlighting</a></h4>
<p>by <a href="https://github.com/dertuxmalwieder">Cthulhux</a></p>
<h4><a href="https://addons.mozilla.org/en-US/thunderbird/addon/todotxt-extension/">Todo.txt Thunderbird Extension</a></h4>
<p>by <a href="https://github.com/rkokkelk/todo.txt-ext">Roy Kokkelkoren</a></p>
</div>
<div class="span3">
<h3>Mobile</h3>
<h4><a href="http://www.windowsphone.com/en-US/apps/50b1ca07-7e23-4963-a0ba-1536e6913543">Todo.txt for Windows Phone 7</a></h4>
<p>Todo.txt for Windows Phone 7 is a task manager based on the todo.txt file format, by <a href="https://github.com/hartez">E.Z. Hart</a>.</p>
<h4><a href="http://monkeystew.org/apps/">Todo.txt Enyo</a></h4>
<p>A webOS application for managing your todo.txt file written using the EnyoJS framework, by <a href="https://github.com/thrrgilag">thrrgilag</a>.</p>
<h4><a href="https://play.google.com/store/apps/details?id=nl.mpcjanssen.todotxtholo">Simpletask</a></h4>
<p>Powerful todo.txt app for Android, by <a href="http://mpcjanssen.nl/">Mark Janssen</a>. Also available in a <a href="https://play.google.com/store/apps/details?id=nl.mpcjanssen.simpletask">cloudless</a> version.</p>
<h4><a href="https://play.google.com/store/apps/details?id=net.c306.ttsuper">Todo.txt for Android</a></h4>
<p>Todo.txt for Android - simple, efficient, integrated with Dropbox, includes home screen widgets. Supports 6.0 Marshmallow or higher, by <a href="https://c306.net">Aditya Bhaskar</a>.</p>
<h3>Developer Tools</h3>
<h4><a href="https://github.com/samwho/todo-txt-gem">Todo.txt Gem</a></h4>
<p>A RubyGem for parsing todo.txt files, by <a href="https://github.com/samwho">Sam Rose</a>.</p>
<h4><a href="http://search.cpan.org/~andrew/Text-Todo-v0.2.0/lib/Text/Todo.pm">Text::Todo</a></h4>
<p>Perl interface to todotxt files by Andrew Fresh.</p>
</div>
</div>
<div class="row">
<div class="span4 offset8" align="right">
<a href="https://twitter.com/todotxt" class="twitter-follow-button" data-show-count="true" data-lang="en">Follow @todotxt</a><script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
</div>
</div>
</div>
</div>
</div>
<div class="footer">
<div class="fill">
<div class="container">
<div class="row">
<p>Unless otherwise noted, Todo.txt apps published herein are authored by <a href="http://ginatrapani.org/" title="Gina Trapani: The Official Site">Gina Trapani</a> in collaboration with <a href="https://github.com/ginatrapani/todo.txt-cli/contributors">Todo.txt</a> <a href="https://github.com/ginatrapani/todo.txt-touch-ios/contributors">community</a> <a href="https://github.com/ginatrapani/todo.txt-touch/contributors">members</a> and released under the <a href="http://www.gnu.org/copyleft/gpl.html">GNU General Public License</a>.</p>
<p>Todo.txt's icon designed by <a href="http://twitter.com/eJohnR">John Rowley</a>.</p>
<p>The first version of the Todo.txt CLI script was originally <a href="http://lifehacker.com/software/top/geek-to-live--readerwritten-todotxt-manager-173018.php">published in 2006 on Lifehacker</a>.</p>
<p>All software comes as is with no warranty. Do back up your todo.txt before you read another word. Support is available on the <a href="http://groups.yahoo.com/group/todotxt/">Todo.txt community mailing list</a>.</p>
</p>
</div>
</div>
</div>
</div>
<div class="footer footer-btm">
<div class="fill">
<div class="container">
<div class="row">
<p>Copyright &copy; 2006-2016, <a href="http://ginatrapani.org/" title="Gina Trapani">Gina Trapani</a>.<a style="visibility:hidden;" href="https://plus.google.com/113612142759476883204?rel=author">Gina Trapani</a></p>
</div>
</div>
</div>
</div>
<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-436966-1";
urchinTracker();
</script>
</body>
</html>

Binary file not shown.

2
tests/Makefile Normal file
View File

@@ -0,0 +1,2 @@
test:
$(MAKE) -C .. test

219
tests/README Normal file
View File

@@ -0,0 +1,219 @@
todo.sh tests
=============
This directory holds test scripts for todo.sh. The
first part of this short document describes how to run the tests
and read their output.
When fixing the tools or adding enhancements, you are strongly
encouraged to add tests in this directory to cover what you are
trying to fix or enhance. The later part of this short document
describes how your test scripts should be organized.
Running Tests
-------------
The easiest way to run tests is to say "make test" from the top-level.
This runs all the tests.
rm -rf tests/test-results "tests/trash directory"*
cd tests && sh t0000-config.sh
* ok 1: no config file
* ok 2: config file (default location 1)
* ok 3: config file (default location 2)
* ok 4: config file (command line)
* ok 5: config file (env variable)
* passed all 5 test(s)
cd tests && sh t0001-null.sh
* ok 1: null ls
* passed all 1 test(s)
rm -rf tests/test-results
Or you can run each test individually from command line, like
this:
$ ./t0001-null.sh
* ok 1: null ls
* passed all 1 test(s)
You can pass --verbose (or -v), --debug (or -d), and --immediate
(or -i) command line argument to the test, or by setting GIT_TEST_OPTS
appropriately before running "make".
--verbose::
This makes the test more verbose. Specifically, the
command being run and their output if any are also
output.
--debug::
This may help the person who is developing a new test.
It causes the command defined with test_debug to run.
--immediate::
This causes the test to immediately exit upon the first
failed test.
--long-tests::
This causes additional long-running tests to be run (where
available), for more exhaustive testing.
--tee::
In addition to printing the test output to the terminal,
write it to files named 't/test-results/$TEST_NAME.out'.
As the names depend on the tests' file names, it is safe to
run the tests with this option in parallel.
Skipping Tests
--------------
In some environments, certain tests have no way of succeeding
due to platform limitation, such as lack of 'unzip' program, or
filesystem that do not allow arbitrary sequence of non-NUL bytes
as pathnames.
You should be able to say something like
$ SKIP_TESTS=t0000.2 sh ./t0000-config.sh
and even:
$ SKIP_TESTS='t[0-4]??? t91?? t9200.8' make
to omit such tests. The value of the environment variable is a
SP separated list of patterns that tells which tests to skip,
and either can match the "t[0-9]{4}" part to skip the whole
test, or t[0-9]{4} followed by ".$number" to say which
particular test to skip.
Note that some tests in the existing test suite rely on previous
test item, so you cannot arbitrarily disable one and expect the
remainder of test to check what the test originally was intended
to check.
Naming Tests
------------
The test files are named as:
tNNNN-commandname-details.sh
where N is a decimal digit.
First digit tells the family:
0 - the absolute basics and global stuff
1 - basic every-day usage
2 - add ins
Second digit tells the particular command we are testing.
Third digit (optionally) tells the particular switch or group of switches
we are testing.
If you create files under tests/ directory (i.e. here) that is not
the top-level test script, never name the file to match the above
pattern. The Makefile here considers all such files as the
top-level test script and tries to run all of them. A care is
especially needed if you are creating a common test library
file, similar to test-lib.sh, because such a library file may
not be suitable for standalone execution.
Writing Tests
-------------
The test script is written as a shell script. It should start
with the standard "#!/bin/sh" with copyright notices, and an
assignment to variable 'test_description', like this:
#!/bin/sh
#
# Copyright (c) 2005 Junio C Hamano
#
test_description='xxx test (option --frotz)
This test registers the following structure in the cache
and tries to run git-ls-files with option --frotz.'
Source 'test-lib.sh'
--------------------
After assigning test_description, the test script should source
test-lib.sh like this:
. ./test-lib.sh
This test harness library does the following things:
- If the script is invoked with command line argument --help
(or -h), it shows the test_description and exits.
- Creates an empty test directory with an empty todo file
database and chdir(2) into it. This directory is 't/trash directory'
if you must know, but I do not think you care.
- Defines standard test helper functions for your scripts to
use. These functions are designed to make all scripts behave
consistently when command line arguments --verbose (or -v),
--debug (or -d), and --immediate (or -i) is given.
End with test_done
------------------
Your script will be a sequence of tests, using helper functions
from the test harness library. At the end of the script, call
'test_done'.
Test harness library
--------------------
There are a handful helper functions defined in the test harness
library for your script to use.
- test_expect_success <message> <script>
This takes two strings as parameter, and evaluates the
<script>. If it yields success, test is considered
successful. <message> should state what it is testing.
Example:
test_expect_success \
'git-write-tree should be able to write an empty tree.' \
'tree=$(git-write-tree)'
- test_expect_failure <message> <script>
This is NOT the opposite of test_expect_success, but is used
to mark a test that demonstrates a known breakage. Unlike
the usual test_expect_success tests, which say "ok" on
success and "FAIL" on failure, this will say "FIXED" on
success and "still broken" on failure. Failures from these
tests won't cause -i (immediate) to stop.
- test_debug <script>
This takes a single argument, <script>, and evaluates it only
when the test script is started with --debug command line
argument. This is primarily meant for use during the
development of a new test script.
- test_done
Your test script must have test_done at the end. Its purpose
is to summarize successes and failures in the test script and
exit with an appropriate error code.
Credits
-------
This test framework was derived from the framework used by
git itself, written originally by Junio Hamano and licensed
for use under the GPL.

34
tests/aggregate-results.sh Executable file
View File

@@ -0,0 +1,34 @@
#!/bin/sh
fixed=0
success=0
failed=0
broken=0
total=0
for file
do
while read type value
do
case $type in
'')
continue ;;
fixed)
fixed=$(($fixed + $value)) ;;
success)
success=$(($success + $value)) ;;
failed)
failed=$(($failed + $value)) ;;
broken)
broken=$(($broken + $value)) ;;
total)
total=$(($total + $value)) ;;
esac
done <"$file"
done
printf "%-8s%d\n" fixed $fixed
printf "%-8s%d\n" success $success
printf "%-8s%d\n" failed $failed
printf "%-8s%d\n" broken $broken
printf "%-8s%d\n" total $total

61
tests/t0000-config.sh Executable file
View File

@@ -0,0 +1,61 @@
#!/bin/sh
test_description='todo.sh configuration file location
This test just makes sure that todo.sh can find its
config files in the default locations and take arguments
to find it somewhere else.
'
. ./test-lib.sh
# Remove the pre-created todo.cfg to test behavior in its absence
rm -f todo.cfg
echo "Fatal error: Cannot read configuration file $HOME/todo.cfg" > expect
test_expect_success 'no config file' '
todo.sh > output 2>&1 || test_cmp expect output
'
# All the below tests will output the usage message.
cat > expect << EOF
Usage: todo.sh [-fhpantvV] [-d todo_config] action [task_number] [task_description]
Try 'todo.sh -h' for more information.
EOF
cat > test.cfg << EOF
export TODO_DIR=.
export TODO_FILE="$TODO_DIR/todo.txt"
export DONE_FILE="$TODO_DIR/done.txt"
export REPORT_FILE="$TODO_DIR/report.txt"
export TMP_FILE="$TODO_DIR/todo.tmp"
touch used_config
EOF
rm -f used_config
test_expect_success 'config file (default location 1)' '
cp test.cfg todo.cfg
todo.sh > output;
test_cmp expect output && test -f used_config &&
rm -f todo.cfg
'
rm -f used_config
test_expect_success 'config file (default location 2)' '
cp test.cfg .todo.cfg
todo.sh > output;
test_cmp expect output && test -f used_config &&
rm -f .todo.cfg
'
rm -f used_config
test_expect_success 'config file (command line)' '
todo.sh -d test.cfg > output;
test_cmp expect output && test -f used_config
'
rm -f used_config
test_expect_success 'config file (env variable)' '
TODOTXT_CFG_FILE=test.cfg todo.sh > output;
test_cmp expect output && test -f used_config
'
test_done

101
tests/t0001-null.sh Executable file
View File

@@ -0,0 +1,101 @@
#!/bin/sh
test_description='todo.sh basic null functionality test.
This test just makes sure the basic commands work,
when there are no todos.
'
. ./test-lib.sh
#
# ls|list
#
cat > expect <<EOF
--
TODO: 0 of 0 tasks shown from $HOME/todo.txt
EOF
test_expect_success 'null ls' '
todo.sh ls > output && test_cmp expect output
'
test_expect_success 'null list' '
todo.sh list > output && test_cmp expect output
'
test_expect_success 'null list filter' '
todo.sh list filter > output && test_cmp expect output
'
#
# lsp|listpri
#
# Re-use expect from ls.
test_expect_success 'null lsp' '
todo.sh lsp > output && test_cmp expect output
'
test_expect_success 'null listpri' '
todo.sh listpri > output && test_cmp expect output
'
test_expect_success 'null listpri a' '
todo.sh listpri a > output && test_cmp expect output
'
#
# lsa|listall
#
cat > expect <<EOF
--
TODO: 0 of 0 tasks shown from $HOME/todo.tmp
EOF
test_expect_success 'null lsa' '
todo.sh lsa > output && test_cmp expect output
'
test_expect_success 'null list' '
todo.sh listall > output && test_cmp expect output
'
test_expect_success 'null list filter' '
todo.sh listall filter > output && test_cmp expect output
'
#
# lsc|listcon
#
test_expect_success 'null lsc' '
todo.sh lsc > output && ! test -s output
'
test_expect_success 'null listcon' '
todo.sh listcon > output && ! test -s output
'
#
# lsprj|listproj
#
test_expect_success 'null lsprj' '
todo.sh lsprj > output && ! test -s output
'
test_expect_success 'null listproj' '
todo.sh listproj > output && ! test -s output
'
#
# lf|listfile
#
cat > expect <<EOF
TODO: File does not exist.
EOF
# XXX really should give a better usage error message here.
test_expect_success 'null lf' '
todo.sh lf > output || test_cmp expect output
'
test_expect_success 'null listfile' '
todo.sh listfile > output || test_cmp expect output
'
cat > expect <<EOF
TODO: File foo.txt does not exist.
EOF
test_expect_success 'null listfile foo.txt' '
todo.sh listfile foo.txt > output || test_cmp expect output
'
test_done

467
tests/test-lib.sh Normal file
View File

@@ -0,0 +1,467 @@
#!/bin/sh
#
# Copyright (c) 2005 Junio C Hamano
#
# if --tee was passed, write the output not only to the terminal, but
# additionally to the file test-results/$BASENAME.out, too.
case "$TEST_TEE_STARTED, $* " in
done,*)
# do not redirect again
;;
*' --tee '*|*' --va'*)
mkdir -p test-results
BASE=test-results/$(basename "$0" .sh)
(TEST_TEE_STARTED=done ${SHELL-sh} "$0" "$@" 2>&1;
echo $? > $BASE.exit) | tee $BASE.out
test "$(cat $BASE.exit)" = 0
exit
;;
esac
# Keep the original TERM for say_color
ORIGINAL_TERM=$TERM
# For repeatability, reset the environment to known value.
LANG=C
LC_ALL=C
PAGER=cat
TZ=UTC
TERM=dumb
export LANG LC_ALL PAGER TERM TZ
EDITOR=:
VISUAL=:
# Protect ourselves from common misconfiguration to export
# CDPATH into the environment
unset CDPATH
# Protect ourselves from using predefined TODOTXT_CFG_FILE
unset TODOTXT_CFG_FILE
# Each test should start with something like this, after copyright notices:
#
# test_description='Description of this test...
# This test checks if command xyzzy does the right thing...
# '
# . ./test-lib.sh
[ "x$ORIGINAL_TERM" != "xdumb" ] && (
TERM=$ORIGINAL_TERM &&
export TERM &&
[ -t 1 ] &&
tput bold >/dev/null 2>&1 &&
tput setaf 1 >/dev/null 2>&1 &&
tput sgr0 >/dev/null 2>&1
) &&
color=t
while test "$#" -ne 0
do
case "$1" in
-d|--d|--de|--deb|--debu|--debug)
debug=t; shift ;;
-i|--i|--im|--imm|--imme|--immed|--immedi|--immedia|--immediat|--immediate)
immediate=t; shift ;;
-l|--l|--lo|--lon|--long|--long-|--long-t|--long-te|--long-tes|--long-test|--long-tests)
TODOTXT_TEST_LONG=t; export TODOTXT_TEST_LONG; shift ;;
-h|--h|--he|--hel|--help)
help=t; shift ;;
-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
verbose=t; shift ;;
-q|--q|--qu|--qui|--quie|--quiet)
quiet=t; shift ;;
--no-color)
color=; shift ;;
--no-python)
# noop now...
shift ;;
--tee)
shift ;; # was handled already
*)
break ;;
esac
done
if test -n "$color"; then
say_color () {
(
TERM=$ORIGINAL_TERM
export TERM
case "$1" in
error) tput bold; tput setaf 1;; # bold red
skip) tput bold; tput setaf 2;; # bold green
pass) tput setaf 2;; # green
info) tput setaf 3;; # brown
*) test -n "$quiet" && return;;
esac
shift
printf "* %s" "$*"
tput sgr0
echo
)
}
else
say_color() {
test -z "$1" && test -n "$quiet" && return
shift
echo "* $*"
}
fi
error () {
say_color error "error: $*"
trap - EXIT
exit 1
}
say () {
say_color info "$*"
}
test "${test_description}" != "" ||
error "Test script did not set test_description."
if test "$help" = "t"
then
echo "$test_description"
exit 0
fi
exec 5>&1
if test "$verbose" = "t"
then
exec 4>&2 3>&1
else
exec 4>/dev/null 3>/dev/null
fi
test_failure=0
test_count=0
test_fixed=0
test_broken=0
test_success=0
die () {
echo >&5 "FATAL: Unexpected exit with code $?"
exit 1
}
trap 'die' EXIT
# The semantics of the editor variables are that of invoking
# sh -c "$EDITOR \"$@\"" files ...
#
# If our trash directory contains shell metacharacters, they will be
# interpreted if we just set $EDITOR directly, so do a little dance with
# environment variables to work around this.
#
# In particular, quoting isn't enough, as the path may contain the same quote
# that we're using.
test_set_editor () {
FAKE_EDITOR="$1"
export FAKE_EDITOR
VISUAL='"$FAKE_EDITOR"'
export VISUAL
}
# You are not expected to call test_ok_ and test_failure_ directly, use
# the text_expect_* functions instead.
test_ok_ () {
test_success=$(($test_success + 1))
say_color "" " ok $test_count: $@"
}
test_failure_ () {
test_failure=$(($test_failure + 1))
say_color error "FAIL $test_count: $1"
shift
echo "$@" | sed -e 's/^/ /'
test "$immediate" = "" || { trap - EXIT; exit 1; }
}
test_known_broken_ok_ () {
test_fixed=$(($test_fixed+1))
say_color "" " FIXED $test_count: $@"
}
test_known_broken_failure_ () {
test_broken=$(($test_broken+1))
say_color skip " still broken $test_count: $@"
}
test_debug () {
test "$debug" = "" || eval "$1"
}
test_run_ () {
eval >&3 2>&4 "$1"
eval_ret="$?"
return 0
}
test_skip () {
test_count=$(($test_count+1))
to_skip=
for skp in $SKIP_TESTS
do
case $this_test.$test_count in
$skp)
to_skip=t
esac
done
case "$to_skip" in
t)
say_color skip >&3 "skipping test: $@"
say_color skip "skip $test_count: $1"
: true
;;
*)
false
;;
esac
}
test_expect_failure () {
test "$#" = 2 ||
error "bug in the test script: not 2 parameters to test-expect-failure"
if ! test_skip "$@"
then
say >&3 "checking known breakage: $2"
test_run_ "$2"
if [ "$?" = 0 -a "$eval_ret" = 0 ]
then
test_known_broken_ok_ "$1"
else
test_known_broken_failure_ "$1"
fi
fi
echo >&3 ""
}
test_expect_success () {
test "$#" = 2 ||
error "bug in the test script: not 2 parameters to test-expect-success"
if ! test_skip "$@"
then
say >&3 "expecting success: $2"
test_run_ "$2"
if [ "$?" = 0 -a "$eval_ret" = 0 ]
then
test_ok_ "$1"
else
test_failure_ "$@"
fi
fi
echo >&3 ""
}
test_expect_code () {
test "$#" = 3 ||
error "bug in the test script: not 3 parameters to test-expect-code"
if ! test_skip "$@"
then
say >&3 "expecting exit code $1: $3"
test_run_ "$3"
if [ "$?" = 0 -a "$eval_ret" = "$1" ]
then
test_ok_ "$2"
else
test_failure_ "$@"
fi
fi
echo >&3 ""
}
# test_external runs external test scripts that provide continuous
# test output about their progress, and succeeds/fails on
# zero/non-zero exit code. It outputs the test output on stdout even
# in non-verbose mode, and announces the external script with "* run
# <n>: ..." before running it. When providing relative paths, keep in
# mind that all scripts run in "trash directory".
# Usage: test_external description command arguments...
# Example: test_external 'Perl API' perl ../path/to/test.pl
test_external () {
test "$#" -eq 3 ||
error >&5 "bug in the test script: not 3 parameters to test_external"
descr="$1"
shift
if ! test_skip "$descr" "$@"
then
# Announce the script to reduce confusion about the
# test output that follows.
say_color "" " run $test_count: $descr ($*)"
# Run command; redirect its stderr to &4 as in
# test_run_, but keep its stdout on our stdout even in
# non-verbose mode.
"$@" 2>&4
if [ "$?" = 0 ]
then
test_ok_ "$descr"
else
test_failure_ "$descr" "$@"
fi
fi
}
# Like test_external, but in addition tests that the command generated
# no output on stderr.
test_external_without_stderr () {
# The temporary file has no (and must have no) security
# implications.
tmp="$TMPDIR"; if [ -z "$tmp" ]; then tmp=/tmp; fi
stderr="$tmp/todotxt-external-stderr.$$.tmp"
test_external "$@" 4> "$stderr"
[ -f "$stderr" ] || error "Internal error: $stderr disappeared."
descr="no stderr: $1"
shift
say >&3 "expecting no stderr from previous command"
if [ ! -s "$stderr" ]; then
rm "$stderr"
test_ok_ "$descr"
else
if [ "$verbose" = t ]; then
output=`echo; echo Stderr is:; cat "$stderr"`
else
output=
fi
# rm first in case test_failure exits.
rm "$stderr"
test_failure_ "$descr" "$@" "$output"
fi
}
# This is not among top-level (test_expect_success | test_expect_failure)
# but is a prefix that can be used in the test script, like:
#
# test_expect_success 'complain and die' '
# do something &&
# do something else &&
# test_must_fail git checkout ../outerspace
# '
#
# Writing this as "! git checkout ../outerspace" is wrong, because
# the failure could be due to a segv. We want a controlled failure.
test_must_fail () {
"$@"
test $? -gt 0 -a $? -le 129 -o $? -gt 192
}
# test_cmp is a helper function to compare actual and expected output.
# You can use it like:
#
# test_expect_success 'foo works' '
# echo expected >expected &&
# foo >actual &&
# test_cmp expected actual
# '
#
# This could be written as either "cmp" or "diff -u", but:
# - cmp's output is not nearly as easy to read as diff -u
# - not all diff versions understand "-u"
test_cmp() {
diff -u "$@"
}
test_done () {
trap - EXIT
test_results_dir="$TEST_DIRECTORY/test-results"
mkdir -p "$test_results_dir"
test_results_path="$test_results_dir/${0%.sh}-$$"
echo "total $test_count" >> $test_results_path
echo "success $test_success" >> $test_results_path
echo "fixed $test_fixed" >> $test_results_path
echo "broken $test_broken" >> $test_results_path
echo "failed $test_failure" >> $test_results_path
echo "" >> $test_results_path
if test "$test_fixed" != 0
then
say_color pass "fixed $test_fixed known breakage(s)"
fi
if test "$test_broken" != 0
then
say_color error "still have $test_broken known breakage(s)"
msg="remaining $(($test_count-$test_broken)) test(s)"
else
msg="$test_count test(s)"
fi
case "$test_failure" in
0)
say_color pass "passed all $msg"
# Clean up this test.
test -d "$remove_trash" &&
cd "$(dirname "$remove_trash")" &&
rm -rf "$(basename "$remove_trash")"
exit 0 ;;
*)
say_color error "failed $test_failure among $msg"
exit 1 ;;
esac
}
# Make sure we are testing the latest version.
TEST_DIRECTORY=$(pwd)
PATH=$TEST_DIRECTORY/..:$PATH
# Test repository
test="trash directory.$(basename "$0" .sh)"
test ! -z "$debug" || remove_trash="$TEST_DIRECTORY/$test"
rm -fr "$test" || {
trap - EXIT
echo >&5 "FATAL: Cannot prepare test area"
exit 1
}
# Most tests can use the created repository, but some may need to create more.
# Usage: test_init_todo <directory>
test_init_todo () {
test "$#" = 1 ||
error "bug in the test script: not 1 parameter to test_init_todo"
owd=`pwd`
root="$1"
mkdir -p "$root"
cd "$root" || error "Cannot setup todo dir in $root"
# Initialize the configuration file. Carefully quoted.
sed -e 's|TODO_DIR=.*$|TODO_DIR="'"$TEST_DIRECTORY/$test"'"|' $TEST_DIRECTORY/../todo.cfg > todo.cfg
cd "$owd"
}
test_init_todo "$test"
# Use -P to resolve symlinks in our working directory so that the cwd
# in subprocesses equals our $PWD (for pathname comparisons).
cd -P "$test" || exit 1
# Since todo.sh refers to the home directory often,
# make sure we don't accidentally grab the tester's config
# but use something specified by the framework.
HOME=$(pwd)
export HOME
this_test=${0##*/}
this_test=${this_test%%-*}
for skp in $SKIP_TESTS
do
to_skip=
for skp in $SKIP_TESTS
do
case "$this_test" in
$skp)
to_skip=t
esac
done
case "$to_skip" in
t)
say_color skip >&3 "skipping test $this_test altogether"
say_color skip "skip all tests in $this_test"
test_done
esac
done

55
todo.cfg Normal file
View File

@@ -0,0 +1,55 @@
# === EDIT FILE LOCATIONS BELOW ===
# Your todo.txt directory
#export TODO_DIR="/Users/gina/Documents/todo"
export TODO_DIR="C:/Documents and Settings/gina/My Documents"
# Your todo/done/report.txt locations
export TODO_FILE="$TODO_DIR/todo.txt"
export DONE_FILE="$TODO_DIR/done.txt"
export REPORT_FILE="$TODO_DIR/report.txt"
export TMP_FILE="$TODO_DIR/todo.tmp"
# You can customize your actions directory location
#export TODO_ACTIONS_DIR="$HOME/.todo.actions.d"
# == EDIT FILE LOCATIONS ABOVE ===
# === COLOR MAP ===
## If you have re-mapped your color codes, you may need to
## over-ride by uncommenting and editing these defaults.
# export BLACK='\\033[0;30m'
# export RED='\\033[0;31m'
# export GREEN='\\033[0;32m'
# export BROWN='\\033[0;33m'
# export BLUE='\\033[0;34m'
# export PURPLE='\\033[0;35m'
# export CYAN='\\033[0;36m'
# export LIGHT_GREY='\\033[0;37m'
# export DARK_GREY='\\033[1;30m'
# export LIGHT_RED='\\033[1;31m'
# export LIGHT_GREEN='\\033[1;32m'
# export YELLOW='\\033[1;33m'
# export LIGHT_BLUE='\\033[1;34m'
# export LIGHT_PURPLE='\\033[1;35m'
# export LIGHT_CYAN='\\033[1;36m'
# export WHITE='\\033[1;37m'
# export DEFAULT='\\033[0m'
# === PRIORITY COLORS ===
## Priorities can be any upper-case letter.
## Colors are supported for the first three.
## Uncomment and edit to override these defaults.
# export PRI_A=$YELLOW # color for A priority
# export PRI_B=$GREEN # color for B priority
# export PRI_C=$LIGHT_BLUE # color for C priority
# export PRI_X=$WHITE # color for rest of them
# === BEHAVIOR ===
## customize list output
# export TODOTXT_SORT_COMMAND='env LC_COLLATE=C sort -f -k2'

895
todo.sh Executable file
View File

@@ -0,0 +1,895 @@
#! /bin/bash
# NOTE: Todo.sh requires the todo.cfg configuration file to run.
# Place the todo.cfg file in your home directory or use the -d option for a custom location.
[ -f VERSION-FILE ] && . VERSION-FILE || VERSION="@DEV_VERSION@"
version() { sed -e 's/^ //' <<EndVersion
TODO.TXT Command Line Interface v$VERSION
First release: 5/11/2006
Original conception by: Gina Trapani (http://ginatrapani.org)
Contributors: http://github.com/ginatrapani/todo.txt-cli/network
License: GPL, http://www.gnu.org/copyleft/gpl.html
More information and mailing list at http://todotxt.com
Code repository: http://github.com/ginatrapani/todo.txt-cli/tree/master
EndVersion
exit 1
}
oneline_usage="todo.sh [-fhpantvV] [-d todo_config] action [task_number] [task_description]"
usage()
{
sed -e 's/^ //' <<EndUsage
Usage: $oneline_usage
Try 'todo.sh -h' for more information.
EndUsage
exit 1
}
shorthelp()
{
sed -e 's/^ //' <<EndHelp
Usage: $oneline_usage
Actions:
add|a "THING I NEED TO DO +project @context"
addto DEST "TEXT TO ADD"
append|app NUMBER "TEXT TO APPEND"
archive
command [ACTIONS]
del|rm NUMBER [TERM]
dp|depri NUMBER
do NUMBER
help
list|ls [TERM...]
listall|lsa [TERM...]
listcon|lsc
listfile|lf SRC [TERM...]
listpri|lsp [PRIORITY]
listproj|lsprj
move|mv NUMBER DEST [SRC]
prepend|prep NUMBER "TEXT TO PREPEND"
pri|p NUMBER PRIORITY
replace NUMBER "UPDATED TODO"
report
See "help" for more details.
EndHelp
exit 0
}
help()
{
sed -e 's/^ //' <<EndHelp
Usage: $oneline_usage
Actions:
add "THING I NEED TO DO +project @context"
a "THING I NEED TO DO +project @context"
Adds THING I NEED TO DO to your todo.txt file on its own line.
Project and context notation optional.
Quotes optional.
addto DEST "TEXT TO ADD"
Adds a line of text to any file located in the todo.txt directory.
For example, addto inbox.txt "decide about vacation"
append NUMBER "TEXT TO APPEND"
app NUMBER "TEXT TO APPEND"
Adds TEXT TO APPEND to the end of the todo on line NUMBER.
Quotes optional.
archive
Moves done items from todo.txt to done.txt and removes blank lines.
command [ACTIONS]
Runs the remaining arguments using only todo.sh builtins.
Will not call any .todo.actions.d scripts.
del NUMBER [TERM]
rm NUMBER [TERM]
Deletes the item on line NUMBER in todo.txt.
If term specified, deletes only the term from the line.
depri NUMBER
dp NUMBER
Deprioritizes (removes the priority) from the item
on line NUMBER in todo.txt.
do NUMBER
Marks item on line NUMBER as done in todo.txt.
help
Display this help message.
list [TERM...]
ls [TERM...]
Displays all todo's that contain TERM(s) sorted by priority with line
numbers. If no TERM specified, lists entire todo.txt.
listall [TERM...]
lsa [TERM...]
Displays all the lines in todo.txt AND done.txt that contain TERM(s)
sorted by priority with line numbers. If no TERM specified, lists
entire todo.txt AND done.txt concatenated and sorted.
listcon
lsc
Lists all the task contexts that start with the @ sign in todo.txt.
listfile SRC [TERM...]
lf SRC [TERM...]
Displays all the lines in SRC file located in the todo.txt directory,
sorted by priority with line numbers. If TERM specified, lists
all lines that contain TERM in SRC file.
listpri [PRIORITY]
lsp [PRIORITY]
Displays all items prioritized PRIORITY.
If no PRIORITY specified, lists all prioritized items.
listproj
lsprj
Lists all the projects that start with the + sign in todo.txt.
move NUMBER DEST [SRC]
mv NUMBER DEST [SRC]
Moves a line from source text file (SRC) to destination text file (DEST).
Both source and destination file must be located in the directory defined
in the configuration directory. When SRC is not defined
it's by default todo.txt.
prepend NUMBER "TEXT TO PREPEND"
prep NUMBER "TEXT TO PREPEND"
Adds TEXT TO PREPEND to the beginning of the todo on line NUMBER.
Quotes optional.
pri NUMBER PRIORITY
p NUMBER PRIORITY
Adds PRIORITY to todo on line NUMBER. If the item is already
prioritized, replaces current priority with new PRIORITY.
PRIORITY must be an uppercase letter between A and Z.
replace NUMBER "UPDATED TODO"
Replaces todo on line NUMBER with UPDATED TODO.
report
Adds the number of open todo's and closed done's to report.txt.
Options:
-@
Hide context names in list output. Use twice to show context
names (default).
-+
Hide project names in list output. Use twice to show project
names (default).
-d CONFIG_FILE
Use a configuration file other than the default ~/todo.cfg
-f
Forces actions without confirmation or interactive input
-h
Display a short help message
-p
Plain mode turns off colors
-P
Hide priority labels in list output. Use twice to show
priority labels (default).
-a
Don't auto-archive tasks automatically on completion
-n
Don't preserve line numbers; automatically remove blank lines
on task deletion
-t
Prepend the current date to a task automatically
when it's added.
-v
Verbose mode turns on confirmation messages
-vv
Extra verbose mode prints some debugging information
-V
Displays version, license and credits
Environment variables:
TODOTXT_AUTO_ARCHIVE=0 is same as option -a
TODOTXT_CFG_FILE=CONFIG_FILE is same as option -d CONFIG_FILE
TODOTXT_FORCE=1 is same as option -f
TODOTXT_PRESERVE_LINE_NUMBERS=0 is same as option -n
TODOTXT_PLAIN=1 is same as option -p
TODOTXT_DATE_ON_ADD=1 is same as option -t
TODOTXT_VERBOSE=1 is same as option -v
TODOTXT_DEFAULT_ACTION="" run this when called with no arguments
TODOTXT_SORT_COMMAND="sort ..." customize list output
EndHelp
if [ -d "$TODO_ACTIONS_DIR" ]
then
echo ""
for action in "$TODO_ACTIONS_DIR"/*
do
if [ -x "$action" ]
then
"$action" usage
fi
done
echo ""
fi
exit 1
}
die()
{
echo "$*"
exit 1
}
cleanup()
{
[ -f "$TMP_FILE" ] && rm "$TMP_FILE"
exit 0
}
archive()
{
#defragment blank lines
sed -i.bak -e '/./!d' "$TODO_FILE"
[ $TODOTXT_VERBOSE -gt 0 ] && grep "^x " "$TODO_FILE"
grep "^x " "$TODO_FILE" >> "$DONE_FILE"
sed -i.bak '/^x /d' "$TODO_FILE"
cp "$TODO_FILE" "$TMP_FILE"
sed -n 'G; s/\n/&&/; /^\([ -~]*\n\).*\n\1/d; s/\n//; h; P' "$TMP_FILE" > "$TODO_FILE"
#[[ $TODOTXT_VERBOSE -gt 0 ]] && echo "TODO: Duplicate tasks have been removed."
[ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: $TODO_FILE archived."
cleanup
}
# == PROCESS OPTIONS ==
while getopts ":fhpnatvV+@Pd:" Option
do
case $Option in
'@' )
## HIDE_CONTEXT_NAMES starts at zero (false); increment it to one
## (true) the first time this flag is seen. Each time the flag
## is seen after that, increment it again so that an even
## number hides project names and an odd number shows project
## names.
: $(( HIDE_CONTEXT_NAMES++ ))
if [ $(( $HIDE_CONTEXT_NAMES % 2 )) -eq 0 ]
then
## Zero or even value -- show context names
unset HIDE_CONTEXTS_SUBSTITUTION
else
## One or odd value -- hide context names
export HIDE_CONTEXTS_SUBSTITUTION='[[:space:]]@[^[:space:]]\{1,\}'
fi
;;
'+' )
## HIDE_PROJECT_NAMES starts at zero (false); increment it to one
## (true) the first time this flag is seen. Each time the flag
## is seen after that, increment it again so that an even
## number hides project names and an odd number shows project
## names.
: $(( HIDE_PROJECT_NAMES++ ))
if [ $(( $HIDE_PROJECT_NAMES % 2 )) -eq 0 ]
then
## Zero or even value -- show project names
unset HIDE_PROJECTS_SUBSTITUTION
else
## One or odd value -- hide project names
export HIDE_PROJECTS_SUBSTITUTION='[[:space:]][+][^[:space:]]\{1,\}'
fi
;;
a )
TODOTXT_AUTO_ARCHIVE=0
;;
d )
TODOTXT_CFG_FILE=$OPTARG
;;
f )
TODOTXT_FORCE=1
;;
h )
shorthelp
;;
n )
TODOTXT_PRESERVE_LINE_NUMBERS=0
;;
p )
TODOTXT_PLAIN=1
;;
P )
## HIDE_PRIORITY_LABELS starts at zero (false); increment it to one
## (true) the first time this flag is seen. Each time the flag
## is seen after that, increment it again so that an even
## number hides project names and an odd number shows project
## names.
: $(( HIDE_PRIORITY_LABELS++ ))
if [ $(( $HIDE_PRIORITY_LABELS % 2 )) -eq 0 ]
then
## Zero or even value -- show priority labels
unset HIDE_PRIORITY_SUBSTITUTION
else
## One or odd value -- hide priority labels
export HIDE_PRIORITY_SUBSTITUTION="([A-Z])[[:space:]]"
fi
;;
t )
TODOTXT_DATE_ON_ADD=1
;;
v )
: $(( TODOTXT_VERBOSE++ ))
;;
V )
version
;;
esac
done
shift $(($OPTIND - 1))
# defaults if not yet defined
TODOTXT_VERBOSE=${TODOTXT_VERBOSE:-1}
TODOTXT_PLAIN=${TODOTXT_PLAIN:-0}
TODOTXT_CFG_FILE=${TODOTXT_CFG_FILE:-$HOME/todo.cfg}
TODOTXT_FORCE=${TODOTXT_FORCE:-0}
TODOTXT_PRESERVE_LINE_NUMBERS=${TODOTXT_PRESERVE_LINE_NUMBERS:-1}
TODOTXT_AUTO_ARCHIVE=${TODOTXT_AUTO_ARCHIVE:-1}
TODOTXT_DATE_ON_ADD=${TODOTXT_DATE_ON_ADD:-0}
TODOTXT_DEFAULT_ACTION=${TODOTXT_DEFAULT_ACTION:-}
TODOTXT_SORT_COMMAND=${TODOTXT_SORT_COMMAND:-env LC_COLLATE=C sort -f -k2}
export TODOTXT_VERBOSE TODOTXT_PLAIN TODOTXT_CFG_FILE TODOTXT_FORCE TODOTXT_PRESERVE_LINE_NUMBERS TODOTXT_AUTO_ARCHIVE TODOTXT_DATE_ON_ADD TODOTXT_SORT_COMMAND
# Default color map
export NONE=''
export BLACK='\\033[0;30m'
export RED='\\033[0;31m'
export GREEN='\\033[0;32m'
export BROWN='\\033[0;33m'
export BLUE='\\033[0;34m'
export PURPLE='\\033[0;35m'
export CYAN='\\033[0;36m'
export LIGHT_GREY='\\033[0;37m'
export DARK_GREY='\\033[1;30m'
export LIGHT_RED='\\033[1;31m'
export LIGHT_GREEN='\\033[1;32m'
export YELLOW='\\033[1;33m'
export LIGHT_BLUE='\\033[1;34m'
export LIGHT_PURPLE='\\033[1;35m'
export LIGHT_CYAN='\\033[1;36m'
export WHITE='\\033[1;37m'
export DEFAULT='\\033[0m'
# Default priority->color map.
export PRI_A=$YELLOW # color for A priority
export PRI_B=$GREEN # color for B priority
export PRI_C=$LIGHT_BLUE # color for C priority
export PRI_X=$WHITE # color for rest of them
[ -e "$TODOTXT_CFG_FILE" ] || {
CFG_FILE_ALT="$HOME/.todo.cfg"
if [ -e "$CFG_FILE_ALT" ]
then
TODOTXT_CFG_FILE="$CFG_FILE_ALT"
fi
}
if [ -z "$TODO_ACTIONS_DIR" -o ! -d "$TODO_ACTIONS_DIR" ]
then
TODO_ACTIONS_DIR="$HOME/.todo.actions.d"
export TODO_ACTIONS_DIR
fi
TODO_SH="$0"
export TODO_SH
# === SANITY CHECKS (thanks Karl!) ===
[ -r "$TODOTXT_CFG_FILE" ] || die "Fatal error: Cannot read configuration file $TODOTXT_CFG_FILE"
. "$TODOTXT_CFG_FILE"
ACTION=${1:-$TODOTXT_DEFAULT_ACTION}
[ -z "$ACTION" ] && usage
[ -d "$TODO_DIR" ] || die "Fatal Error: $TODO_DIR is not a directory"
( cd "$TODO_DIR" ) || die "Fatal Error: Unable to cd to $TODO_DIR"
[ -w "$TMP_FILE" ] || echo -n > "$TMP_FILE" || die "Fatal Error: Unable to write to $TMP_FILE"
[ -f "$TODO_FILE" ] || cp /dev/null "$TODO_FILE"
[ -f "$DONE_FILE" ] || cp /dev/null "$DONE_FILE"
[ -f "$REPORT_FILE" ] || cp /dev/null "$REPORT_FILE"
if [ $TODOTXT_PLAIN = 1 ]; then
PRI_A=$NONE
PRI_B=$NONE
PRI_C=$NONE
PRI_X=$NONE
DEFAULT=$NONE
fi
# === HEAVY LIFTING ===
shopt -s extglob
_list() {
local FILE="$1"
## If the file starts with a "/" use absolute path. Otherwise,
## try to find it in either $TODO_DIR or using a relative path
if [ "${1:0:1}" == / ]
then
## Absolute path
src="$FILE"
elif [ -f "$TODO_DIR/$FILE" ]
then
## Path relative to todo.sh directory
src="$TODO_DIR/$1"
elif [ -f "$FILE" ]
then
## Path relative to current working directory
src="$FILE"
else
echo "TODO: File $FILE does not exist."
exit 1
fi
## Get our search arguments, if any
shift ## was file name, new $1 is first search term
## Prefix the filter_command with the pre_filter_command
filter_command="${pre_filter_command:-}"
for search_term in "$@"
do
## See if the first character of $search_term is a dash
if [ ${search_term:0:1} != '-' ]
then
## First character isn't a dash: hide lines that don't match
## this $search_term
filter_command="${filter_command:-} ${filter_command:+|} \
grep -i \"$search_term\" "
else
## First character is a dash: hide lines that match this
## $search_term
#
## Remove the first character (-) before adding to our filter command
filter_command="${filter_command:-} ${filter_command:+|} \
grep -v -i \"${search_term:1}\" "
fi
done
## If post_filter_command is set, append it to the filter_command
[ -n "$post_filter_command" ] && {
filter_command="${filter_command:-}${filter_command:+ | }${post_filter_command:-}"
}
## Figure out how much padding we need to use
## We need one level of padding for each power of 10 $LINES uses
LINES=$( sed -n '$ =' "$src" )
PADDING=${#LINES}
## Number the file, then run the filter command,
## then sort and mangle output some more
items=$(
sed = "$src" \
| sed "N; s/^/ /; s/ *\(.\{$PADDING,\}\)\n/\1 /" \
| grep -v "^[0-9]\+ *$"
)
if [ "${filter_command}" ]; then
filtered_items=$(echo -ne "$items" | eval ${filter_command})
else
filtered_items=$items
fi
filtered_items=$(
echo -ne "$filtered_items" \
| sed '''
s/^ /00000/;
s/^ /0000/;
s/^ /000/;
s/^ /00/;
s/^ /0/;
''' \
| ${TODOTXT_SORT_COMMAND} \
| sed '''
/^[0-9]\{'$PADDING'\} x /! {
s/\(.*(A).*\)/'$PRI_A'\1'$DEFAULT'/g;
s/\(.*(B).*\)/'$PRI_B'\1'$DEFAULT'/g;
s/\(.*(C).*\)/'$PRI_C'\1'$DEFAULT'/g;
s/\(.*([D-Z]).*\)/'$PRI_X'\1'$DEFAULT'/g;
}
''' \
| sed '''
s/'${HIDE_PRIORITY_SUBSTITUTION:-^}'//g
s/'${HIDE_PROJECTS_SUBSTITUTION:-^}'//g
s/'${HIDE_CONTEXTS_SUBSTITUTION:-^}'//g
''' \
)
echo -ne "$filtered_items${filtered_items:+\n}"
if [ $TODOTXT_VERBOSE -gt 0 ]; then
NUMTASKS=$( echo -ne "$filtered_items" | sed -n '$ =' )
TOTALTASKS=$( echo -ne "$items" | sed -n '$ =' )
echo "--"
echo "TODO: ${NUMTASKS:-0} of ${TOTALTASKS:-0} tasks shown from $FILE"
fi
if [ $TODOTXT_VERBOSE -gt 1 ]
then
echo "TODO DEBUG: Filter Command was: ${filter_command:-cat}"
fi
}
export -f _list
# == HANDLE ACTION ==
action=$( printf "%s\n" "$ACTION" | tr 'A-Z' 'a-z' )
## If the first argument is "command", run the rest of the arguments
## using todo.sh builtins.
## Else, run a actions script with the name of the command if it exists
## or fallback to using a builtin
if [ "$action" == command ]
then
## Get rid of "command" from arguments list
shift
## Reset action to new first argument
action=$( printf "%s\n" "$1" | tr 'A-Z' 'a-z' )
elif [ -d "$TODO_ACTIONS_DIR" -a -x "$TODO_ACTIONS_DIR/$action" ]
then
"$TODO_ACTIONS_DIR/$action" "$@"
cleanup
fi
## Only run if $action isn't found in .todo.actions.d
case $action in
"add" | "a")
if [[ -z "$2" && $TODOTXT_FORCE = 0 ]]; then
echo -n "Add: "
read input
else
[ -z "$2" ] && die "usage: $0 add \"TODO ITEM\""
shift
input=$*
fi
if [[ $TODOTXT_DATE_ON_ADD = 1 ]]; then
now=`date '+%Y-%m-%d'`
input="$now $input"
fi
echo "$input" >> "$TODO_FILE"
TASKNUM=$(sed -n '$ =' "$TODO_FILE")
[ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: '$input' added on line $TASKNUM."
cleanup;;
"addto" )
[ -z "$2" ] && die "usage: $0 addto DEST \"TODO ITEM\""
dest="$TODO_DIR/$2"
[ -z "$3" ] && die "usage: $0 addto DEST \"TODO ITEM\""
shift
shift
input=$*
if [ -f "$dest" ]; then
echo "$input" >> "$dest"
TASKNUM=$(sed -n '$ =' "$dest")
[ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: '$input' added to $dest on line $TASKNUM."
else
echo "TODO: Destination file $dest does not exist."
fi
cleanup;;
"append" | "app" )
errmsg="usage: $0 append ITEM# \"TEXT TO APPEND\""
shift; item=$1; shift
[ -z "$item" ] && die "$errmsg"
[[ "$item" = +([0-9]) ]] || die "$errmsg"
todo=$(sed "$item!d" "$TODO_FILE")
[ -z "$todo" ] && die "$item: No such todo."
if [[ -z "$1" && $TODOTXT_FORCE = 0 ]]; then
echo -n "Append: "
read input
else
input=$*
fi
if sed -i.bak $item" s|^.*|& $input|" "$TODO_FILE"; then
newtodo=$(sed "$item!d" "$TODO_FILE")
[ $TODOTXT_VERBOSE -gt 0 ] && echo "$item: $newtodo"
else
echo "TODO: Error appending task $item."
fi
cleanup;;
"archive" )
archive;;
"del" | "rm" )
# replace deleted line with a blank line when TODOTXT_PRESERVE_LINE_NUMBERS is 1
errmsg="usage: $0 del ITEM#"
item=$2
[ -z "$item" ] && die "$errmsg"
if [ -z "$3" ]; then
[[ "$item" = +([0-9]) ]] || die "$errmsg"
if sed -ne "$item p" "$TODO_FILE" | grep "^."; then
DELETEME=$(sed "$item!d" "$TODO_FILE")
if [ $TODOTXT_FORCE = 0 ]; then
echo "Delete '$DELETEME'? (y/n)"
read ANSWER
else
ANSWER="y"
fi
if [ "$ANSWER" = "y" ]; then
if [ $TODOTXT_PRESERVE_LINE_NUMBERS = 0 ]; then
# delete line (changes line numbers)
sed -i.bak -e $item"s/^.*//" -e '/./!d' "$TODO_FILE"
else
# leave blank line behind (preserves line numbers)
sed -i.bak -e $item"s/^.*//" "$TODO_FILE"
fi
[ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: '$DELETEME' deleted."
cleanup
else
echo "TODO: No tasks were deleted."
fi
else
echo "$item: No such todo."
fi
else
sed -i.bak -e $item"s/$3/ /g" "$TODO_FILE"
[ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: $3 removed from $item."
fi ;;
"depri" | "dp" )
item=$2
errmsg="usage: $0 depri ITEM#"
todo=$(sed "$item!d" "$TODO_FILE")
[ -z "$todo" ] && die "$item: No such todo."
[[ "$item" = +([0-9]) ]] || die "$errmsg"
sed -e $item"s/^(.) //" "$TODO_FILE" > /dev/null 2>&1
if [ "$?" -eq 0 ]; then
#it's all good, continue
sed -i.bak -e $item"s/^(.) //" "$TODO_FILE"
NEWTODO=$(sed "$item!d" "$TODO_FILE")
[ $TODOTXT_VERBOSE -gt 0 ] && echo -e "`echo "$item: $NEWTODO"`"
[ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: $item deprioritized."
cleanup
else
die "$errmsg"
fi;;
"do" )
errmsg="usage: $0 do ITEM#"
item=$2
[ -z "$item" ] && die "$errmsg"
[[ "$item" = +([0-9]) ]] || die "$errmsg"
todo=$(sed "$item!d" "$TODO_FILE")
[ -z "$todo" ] && die "$item: No such todo."
now=`date '+%Y-%m-%d'`
# remove priority once item is done
sed -i.bak $item"s/^(.) //" "$TODO_FILE"
sed -i.bak $item"s|^|&x $now |" "$TODO_FILE"
newtodo=$(sed "$item!d" "$TODO_FILE")
[ $TODOTXT_VERBOSE -gt 0 ] && echo "$item: $newtodo"
[ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: $item marked as done."
if [ $TODOTXT_AUTO_ARCHIVE = 1 ]; then
archive
fi
cleanup ;;
"help" )
help
;;
"list" | "ls" )
shift ## Was ls; new $1 is first search term
_list "$TODO_FILE" "$@"
cleanup
;;
"listall" | "lsa" )
shift ## Was lsa; new $1 is first search term
cat "$TODO_FILE" "$DONE_FILE" > "$TMP_FILE"
_list "$TMP_FILE" "$@"
cleanup
;;
"listfile" | "lf" )
shift ## Was listfile, next $1 is file name
FILE="$1"
shift ## Was filename; next $1 is first search term
_list "$FILE" "$@"
cleanup
;;
"listcon" | "lsc" )
grep -w -o '@[^ ]\+' "$TODO_FILE" | sort -u
cleanup ;;
"listproj" | "lsprj" )
grep -w -o '+[^ ]\+' "$TODO_FILE" | sort -u
cleanup ;;
"listpri" | "lsp" )
shift ## was "listpri", new $1 is priority to list
if [ "${1:-}" ]
then
## A priority was specified
pri=$( printf "%s\n" "$1" | tr 'a-z' 'A-Z' | grep '^[A-Z]$' ) || {
die "usage: $0 listpri PRIORITY
note: PRIORITY must a single letter from A to Z."
}
else
## No priority specified; show all priority tasks
pri="[[:upper:]]"
fi
pri="($pri)"
_list "$TODO_FILE" "$pri"
;;
"move" | "mv" )
# replace moved line with a blank line when TODOTXT_PRESERVE_LINE_NUMBERS is 1
errmsg="usage: $0 mv ITEM# DEST [SRC]"
item=$2
dest="$TODO_DIR/$3"
src="$TODO_DIR/$4"
[ -z "$item" ] && die "$errmsg"
[ -z "$4" ] && src="$TODO_FILE"
[ -z "$dest" ] && die "$errmsg"
[[ "$item" = +([0-9]) ]] || die "$errmsg"
if [ -f "$src" ]; then
if [ -f "$dest" ]; then
if sed -ne "$item p" "$src" | grep "^."; then
MOVEME=$(sed "$item!d" "$src")
if [ $TODOTXT_FORCE = 0 ]; then
echo "Move '$MOVEME' from $src to $dest? (y/n)"
read ANSWER
else
ANSWER="y"
fi
if [ "$ANSWER" = "y" ]; then
if [ $TODOTXT_PRESERVE_LINE_NUMBERS = 0 ]; then
# delete line (changes line numbers)
sed -i.bak -e $item"s/^.*//" -e '/./!d' "$src"
else
# leave blank line behind (preserves line numbers)
sed -i.bak -e $item"s/^.*//" "$src"
fi
echo "$MOVEME" >> "$dest"
[ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: '$MOVEME' moved from '$src' to '$dest'."
cleanup
else
echo "TODO: No tasks moved."
fi
else
echo "$item: No such item in $src."
fi
else
echo "TODO: Destination file $dest does not exist."
fi
else
echo "TODO: Source file $src does not exist."
fi
cleanup;;
"prepend" | "prep" )
errmsg="usage: $0 prepend ITEM# \"TEXT TO PREPEND\""
shift; item=$1; shift
[ -z "$item" ] && die "$errmsg"
[[ "$item" = +([0-9]) ]] || die "$errmsg"
todo=$(sed "$item!d" "$TODO_FILE")
[ -z "$todo" ] && die "$item: No such todo."
if [[ -z "$1" && $TODOTXT_FORCE = 0 ]]; then
echo -n "Prepend: "
read input
else
input=$*
fi
if sed -i.bak $item" s|^.*|$input &|" "$TODO_FILE"; then
newtodo=$(sed "$item!d" "$TODO_FILE")
[ $TODOTXT_VERBOSE -gt 0 ] && echo "$item: $newtodo"
else
echo "TODO: Error prepending task $item."
fi
cleanup;;
"pri" | "p" )
item=$2
newpri=$( printf "%s\n" "$3" | tr 'a-z' 'A-Z' )
errmsg="usage: $0 pri ITEM# PRIORITY
note: PRIORITY must be anywhere from A to Z."
[ "$#" -ne 3 ] && die "$errmsg"
[[ "$item" = +([0-9]) ]] || die "$errmsg"
[[ "$newpri" = @([A-Z]) ]] || die "$errmsg"
sed -e $item"s/^(.) //" -e $item"s/^/($newpri) /" "$TODO_FILE" > /dev/null 2>&1
if [ "$?" -eq 0 ]; then
#it's all good, continue
sed -i.bak -e $item"s/^(.) //" -e $item"s/^/($newpri) /" "$TODO_FILE"
NEWTODO=$(sed "$item!d" "$TODO_FILE")
[ $TODOTXT_VERBOSE -gt 0 ] && echo -e "`echo "$item: $NEWTODO"`"
[ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: $item prioritized ($newpri)."
cleanup
else
die "$errmsg"
fi;;
"replace" )
errmsg="usage: $0 replace ITEM# \"UPDATED ITEM\""
shift; item=$1; shift
[ -z "$item" ] && die "$errmsg"
[[ "$item" = +([0-9]) ]] || die "$errmsg"
todo=$(sed "$item!d" "$TODO_FILE")
[ -z "$todo" ] && die "$item: No such todo."
if [[ -z "$1" && $TODOTXT_FORCE = 0 ]]; then
echo -n "Replacement: "
read input
else
input=$*
fi
sed -i.bak $item" s|^.*|$input|" "$TODO_FILE"
[ $TODOTXT_VERBOSE -gt 0 ] && NEWTODO=$(head -$item "$TODO_FILE" | tail -1)
[ $TODOTXT_VERBOSE -gt 0 ] && echo "$item: $todo"
[ $TODOTXT_VERBOSE -gt 0 ] && echo "replaced with"
[ $TODOTXT_VERBOSE -gt 0 ] && echo "$item: $NEWTODO"
cleanup;;
"report" )
#archive first
sed '/^x /!d' "$TODO_FILE" >> "$DONE_FILE"
sed -i.bak '/^x /d' "$TODO_FILE"
NUMLINES=$( sed -n '$ =' "$TODO_FILE" )
if [ ${NUMLINES:-0} = "0" ]; then
echo "datetime todos dones" >> "$REPORT_FILE"
fi
#now report
TOTAL=$( sed -n '$ =' "$TODO_FILE" )
TDONE=$( sed -n '$ =' "$DONE_FILE" )
TECHO=$(echo $(date +%Y-%m-%d-%T); echo ' '; echo ${TOTAL:-0}; echo ' ';
echo ${TDONE:-0})
echo $TECHO >> "$REPORT_FILE"
[ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: Report file updated."
cat "$REPORT_FILE"
cleanup;;
* )
usage
;;
esac

View File

@@ -1,8 +0,0 @@
(A) Call Mom @Phone +Family
(A) Schedule annual checkup +Health
(B) Outline chapter 5 +Novel @Computer
(C) Add cover sheets @Office +TPSReports
Plan backyard herb garden @Home
Pick up milk @GroceryStore
Research self-publishing services +Novel @Computer
x Download Todo.txt mobile app @Phone