Compare commits

..

63 Commits
v2.1.0 ... v2.3

Author SHA1 Message Date
U-STARBUCK\gina
1a6ff81e28 Makefile infrastructure 2009-04-02 21:01:44 -07: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
ginatrapani
7bd6696540 2009-03-05 19:49:13 -07:00
ginatrapani
b5a03cfee5 2009-03-05 19:47:20 -07:00
ginatrapani
d7b9f87994 Updated name and background color 2009-03-05 19:46:27 -07:00
ginatrapani
959598416f github generated gh-pages branch 2009-03-05 19:07:23 -07:00
U-STARBUCK\gina
25c6505007 Shortened README 2009-03-05 17:56:56 -08:00
6 changed files with 721 additions and 597 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
VERSION-FILE

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
}

34
Makefile Normal file
View File

@@ -0,0 +1,34 @@
#
# 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
.PHONY: test
test:
@echo "TBD!"

119
README
View File

@@ -1,111 +1,8 @@
Usage: todo.sh [-fhpantvV] [-d todo_config] action [task_number] [task_description] TODO.TXT Command Line Interface
Latest version: http://github.com/ginatrapani/todo.txt-cli/tree/master
Actions: First release: 5/11/2006
add "THING I NEED TO DO +project @context" Conceived and released by: Gina Trapani (http://ginatrapani.org)
a "THING I NEED TO DO +project @context" Contributors: http://github.com/ginatrapani/todo.txt-cli/network
Adds THING I NEED TO DO to your todo.txt file on its own line. License: GPL, http://www.gnu.org/copyleft/gpl.html
Project and context notation optional. More information and mailing list at http://todotxt.com
Quotes optional. To submit patches, fork the repository at http://github.com/ginatrapani/todo.txt-cli/tree/master
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.
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.
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:
-d CONFIG_FILE
Use a configuration file other than the default ~/todo.cfg
-f
Forces actions without confirmation or interactive input
-h
Display this help message
-p
Plain mode turns off colors
-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
-V
Displays version, license and credits

View File

@@ -1,41 +1,41 @@
# === EDIT FILE LOCATIONS BELOW === # === EDIT FILE LOCATIONS BELOW ===
# Your todo.txt directory # Your todo.txt directory
#TODO_DIR="/Users/gina/Documents/todo" #export TODO_DIR="/Users/gina/Documents/todo"
TODO_DIR="C:/Documents and Settings/gina/My Documents" export TODO_DIR="C:/Documents and Settings/gina/My Documents"
# Your todo/done/report.txt locations # Your todo/done/report.txt locations
TODO_FILE="$TODO_DIR/todo.txt" export TODO_FILE="$TODO_DIR/todo.txt"
DONE_FILE="$TODO_DIR/done.txt" export DONE_FILE="$TODO_DIR/done.txt"
REPORT_FILE="$TODO_DIR/report.txt" export REPORT_FILE="$TODO_DIR/report.txt"
TMP_FILE="$TODO_DIR/todo.tmp" export TMP_FILE="$TODO_DIR/todo.tmp"
# == EDIT FILE LOCATIONS ABOVE === # == EDIT FILE LOCATIONS ABOVE ===
# === COLOR MAP === # === COLOR MAP ===
NONE='' export NONE=''
BLACK='\\033[0;30m' export BLACK='\\033[0;30m'
RED='\\033[0;31m' export RED='\\033[0;31m'
GREEN='\\033[0;32m' export GREEN='\\033[0;32m'
BROWN='\\033[0;33m' export BROWN='\\033[0;33m'
BLUE='\\033[0;34m' export BLUE='\\033[0;34m'
PURPLE='\\033[0;35m' export PURPLE='\\033[0;35m'
CYAN='\\033[0;36m' export CYAN='\\033[0;36m'
LIGHT_GREY='\\033[0;37m' export LIGHT_GREY='\\033[0;37m'
DARK_GREY='\\033[1;30m' export DARK_GREY='\\033[1;30m'
LIGHT_RED='\\033[1;31m' export LIGHT_RED='\\033[1;31m'
LIGHT_GREEN='\\033[1;32m' export LIGHT_GREEN='\\033[1;32m'
YELLOW='\\033[1;33m' export YELLOW='\\033[1;33m'
LIGHT_BLUE='\\033[1;34m' export LIGHT_BLUE='\\033[1;34m'
LIGHT_PURPLE='\\033[1;35m' export LIGHT_PURPLE='\\033[1;35m'
LIGHT_CYAN='\\033[1;36m' export LIGHT_CYAN='\\033[1;36m'
WHITE='\\033[1;37m' export WHITE='\\033[1;37m'
DEFAULT='\\033[0m' export DEFAULT='\\033[0m'
# === PRIORITY COLORS === # === PRIORITY COLORS ===
PRI_A=$YELLOW # color for A priority export PRI_A=$YELLOW # color for A priority
PRI_B=$GREEN # color for B priority export PRI_B=$GREEN # color for B priority
PRI_C=$LIGHT_BLUE # color for C priority export PRI_C=$LIGHT_BLUE # color for C priority
PRI_X=$WHITE # color for rest of them export PRI_X=$WHITE # color for rest of them

556
todo.sh Normal file → Executable file
View File

@@ -3,32 +3,67 @@
# NOTE: Todo.sh requires the todo.cfg configuration file to run. # 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. # 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 version() { sed -e 's/^ //' <<EndVersion
TODO.TXT Manager TODO.TXT Command Line Interface v$VERSION
Version 2.1
Author: Gina Trapani (ginatrapani@gmail.com) First release: 5/11/2006
Last updated: 2/23/2009 Original conception by: Gina Trapani (http://ginatrapani.org)
Release date: 5/11/2006 Contributors: http://github.com/ginatrapani/todo.txt-cli/network
License: GPL, http://www.gnu.org/copyleft/gpl.html License: GPL, http://www.gnu.org/copyleft/gpl.html
More information and mailing list at http://todotxt.com More information and mailing list at http://todotxt.com
Code repository: http://github.com/ginatrapani/todo.txt-cli/tree/master
EndVersion EndVersion
exit 1 exit 1
} }
oneline_usage="todo.sh [-fhpantvV] [-d todo_config] action [task_number] [task_description]"
usage() usage()
{ {
sed -e 's/^ //' <<EndUsage sed -e 's/^ //' <<EndUsage
Usage: todo.sh [-fhpantvV] [-d todo_config] action [task_number] [task_description] Usage: $oneline_usage
Try 'todo.sh -h' for more information. Try 'todo.sh -h' for more information.
EndUsage EndUsage
exit 1 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() help()
{ {
sed -e 's/^ //' <<EndHelp sed -e 's/^ //' <<EndHelp
Usage: todo.sh [-fhpantvV] [-d todo_config] action [task_number] [task_description] Usage: $oneline_usage
Actions: Actions:
add "THING I NEED TO DO +project @context" add "THING I NEED TO DO +project @context"
@@ -49,6 +84,10 @@ help()
archive archive
Moves done items from todo.txt to done.txt and removes blank lines. 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] del NUMBER [TERM]
rm NUMBER [TERM] rm NUMBER [TERM]
Deletes the item on line NUMBER in todo.txt. Deletes the item on line NUMBER in todo.txt.
@@ -62,6 +101,9 @@ help()
do NUMBER do NUMBER
Marks item on line NUMBER as done in todo.txt. Marks item on line NUMBER as done in todo.txt.
help
Display this help message.
list [TERM...] list [TERM...]
ls [TERM...] ls [TERM...]
Displays all todo's that contain TERM(s) sorted by priority with line Displays all todo's that contain TERM(s) sorted by priority with line
@@ -119,14 +161,23 @@ help()
Options: 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 -d CONFIG_FILE
Use a configuration file other than the default ~/todo.cfg Use a configuration file other than the default ~/todo.cfg
-f -f
Forces actions without confirmation or interactive input Forces actions without confirmation or interactive input
-h -h
Display this help message Display a short help message
-p -p
Plain mode turns off colors Plain mode turns off colors
-P
Hide priority labels in list output. Use twice to show
priority labels (default).
-a -a
Don't auto-archive tasks automatically on completion Don't auto-archive tasks automatically on completion
-n -n
@@ -137,8 +188,21 @@ help()
when it's added. when it's added.
-v -v
Verbose mode turns on confirmation messages Verbose mode turns on confirmation messages
-vv
Extra verbose mode prints some debugging information
-V -V
Displays version, license and credits 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
EndHelp EndHelp
if [ -d "$HOME/.todo.actions.d" ] if [ -d "$HOME/.todo.actions.d" ]
@@ -174,53 +238,92 @@ archive()
{ {
#defragment blank lines #defragment blank lines
sed -i.bak -e '/./!d' "$TODO_FILE" sed -i.bak -e '/./!d' "$TODO_FILE"
[[ $VERBOSE = 1 ]] && grep "^x " "$TODO_FILE" [ $TODOTXT_VERBOSE -gt 0 ] && grep "^x " "$TODO_FILE"
grep "^x " "$TODO_FILE" >> "$DONE_FILE" grep "^x " "$TODO_FILE" >> "$DONE_FILE"
sed -i.bak '/^x /d' "$TODO_FILE" sed -i.bak '/^x /d' "$TODO_FILE"
cp "$TODO_FILE" "$TMP_FILE" cp "$TODO_FILE" "$TMP_FILE"
sed -n 'G; s/\n/&&/; /^\([ -~]*\n\).*\n\1/d; s/\n//; h; P' "$TMP_FILE" > "$TODO_FILE" sed -n 'G; s/\n/&&/; /^\([ -~]*\n\).*\n\1/d; s/\n//; h; P' "$TMP_FILE" > "$TODO_FILE"
#[[ $VERBOSE = 1 ]] && echo "TODO: Duplicate tasks have been removed." #[[ $TODOTXT_VERBOSE -gt 0 ]] && echo "TODO: Duplicate tasks have been removed."
[[ $VERBOSE = 1 ]] && echo "TODO: $TODO_FILE archived." [ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: $TODO_FILE archived."
cleanup cleanup
} }
# == PROCESS OPTIONS == # == PROCESS OPTIONS ==
# defaults while getopts ":fhpnatvV+@Pd:" Option
VERBOSE=1
PLAIN=0
CFG_FILE=$HOME/todo.cfg
FORCE=0
PRESERVE_LINE_NUMBERS=1
AUTO_ARCHIVE=1
DATE_ON_ADD=0
while getopts ":fhpnatvVd:" Option
do do
case $Option in 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 ) a )
AUTO_ARCHIVE=0 TODOTXT_AUTO_ARCHIVE=0
;; ;;
d ) d )
CFG_FILE=$OPTARG TODOTXT_CFG_FILE=$OPTARG
;; ;;
f ) f )
FORCE=1 TODOTXT_FORCE=1
;; ;;
h ) h )
help shorthelp
;; ;;
n ) n )
PRESERVE_LINE_NUMBERS=0 TODOTXT_PRESERVE_LINE_NUMBERS=0
;; ;;
p ) p )
PLAIN=1 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 ) t )
DATE_ON_ADD=1 TODOTXT_DATE_ON_ADD=1
;; ;;
v ) v )
VERBOSE=1 : $(( TODOTXT_VERBOSE++ ))
;; ;;
V ) V )
version version
@@ -229,31 +332,47 @@ do
done done
shift $(($OPTIND - 1)) shift $(($OPTIND - 1))
[ -e "$CFG_FILE" ] || { # 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:-}
[ -e "$TODOTXT_CFG_FILE" ] || {
CFG_FILE_ALT="$HOME/.todo.cfg" CFG_FILE_ALT="$HOME/.todo.cfg"
if [ -e "$CFG_FILE_ALT" ] if [ -e "$CFG_FILE_ALT" ]
then then
CFG_FILE="$CFG_FILE_ALT" TODOTXT_CFG_FILE="$CFG_FILE_ALT"
fi fi
} }
export TODOTXT_VERBOSE TODOTXT_PLAIN TODOTXT_CFG_FILE TODOTXT_FORCE TODOTXT_PRESERVE_LINE_NUMBERS TODOTXT_AUTO_ARCHIVE TODOTXT_DATE_ON_ADD
TODO_SH="$0"
export TODO_SH
# === SANITY CHECKS (thanks Karl!) === # === SANITY CHECKS (thanks Karl!) ===
[ -r "$CFG_FILE" ] || die "Fatal error: Cannot read configuration file $CFG_FILE" [ -r "$TODOTXT_CFG_FILE" ] || die "Fatal error: Cannot read configuration file $TODOTXT_CFG_FILE"
. "$CFG_FILE" . "$TODOTXT_CFG_FILE"
[ -z "$1" ] && usage ACTION=${1:-$TODOTXT_DEFAULT_ACTION}
[ -z "$ACTION" ] && usage
[ -d "$TODO_DIR" ] || die "Fatal Error: $TODO_DIR is not a directory" [ -d "$TODO_DIR" ] || die "Fatal Error: $TODO_DIR is not a directory"
cd "$TODO_DIR" || die "Fatal Error: Unable to cd to $TODO_DIR" ( cd "$TODO_DIR" ) || die "Fatal Error: Unable to cd to $TODO_DIR"
echo '' > "$TMP_FILE" || die "Fatal Error: Unable to write in $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 "$TODO_FILE" ] || cp /dev/null "$TODO_FILE"
[ -f "$DONE_FILE" ] || cp /dev/null "$DONE_FILE" [ -f "$DONE_FILE" ] || cp /dev/null "$DONE_FILE"
[ -f "$REPORT_FILE" ] || cp /dev/null "$REPORT_FILE" [ -f "$REPORT_FILE" ] || cp /dev/null "$REPORT_FILE"
if [ $TODOTXT_PLAIN = 1 ]; then
if [ $PLAIN = 1 ]; then
PRI_A=$NONE PRI_A=$NONE
PRI_B=$NONE PRI_B=$NONE
PRI_C=$NONE PRI_C=$NONE
@@ -264,12 +383,138 @@ fi
# === HEAVY LIFTING === # === HEAVY LIFTING ===
shopt -s extglob shopt -s extglob
# == HANDLE ACTION == _list() {
action=$( printf "%s\n" "$1" | tr 'A-Z' 'a-z' ) 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/;
''' \
| sort -f -k2 \
| 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 "$HOME/.todo.actions.d" -a -x "$HOME/.todo.actions.d/$action" ]
then
"$HOME/.todo.actions.d/$action" "$@"
cleanup
fi
## Only run if $action isn't found in .todo.actions.d
case $action in case $action in
"add" | "a") "add" | "a")
if [[ -z "$2" && $FORCE = 0 ]]; then if [[ -z "$2" && $TODOTXT_FORCE = 0 ]]; then
echo -n "Add: " echo -n "Add: "
read input read input
else else
@@ -278,35 +523,27 @@ case $action in
input=$* input=$*
fi fi
if [[ $TODOTXT_DATE_ON_ADD = 1 ]]; then
if [[ $DATE_ON_ADD = 1 ]]; then
now=`date '+%Y-%m-%d'` now=`date '+%Y-%m-%d'`
input="$now $input" input="$now $input"
fi fi
echo "$input" >> "$TODO_FILE" echo "$input" >> "$TODO_FILE"
TASKNUM=$(sed -n '$ =' "$TODO_FILE")
[ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: '$input' added on line $TASKNUM."
TASKNUM=$(wc -l "$TODO_FILE" | sed 's/^[[:space:]]*\([0-9]*\).*/\1/')
[[ $VERBOSE = 1 ]] && echo "TODO: '$input' added on line $TASKNUM."
cleanup;; cleanup;;
"addto" ) "addto" )
[ -z "$2" ] && die "usage: $0 addto DEST \"TODO ITEM\"" [ -z "$2" ] && die "usage: $0 addto DEST \"TODO ITEM\""
dest="$TODO_DIR/$2" dest="$TODO_DIR/$2"
[ -z "$3" ] && die "usage: $0 addto DEST \"TODO ITEM\"" [ -z "$3" ] && die "usage: $0 addto DEST \"TODO ITEM\""
shift shift
shift shift
input=$* input=$*
if [ -f "$dest" ]; then if [ -f "$dest" ]; then
echo "$input" >> "$dest" echo "$input" >> "$dest"
TASKNUM=$(sed -n '$ =' "$dest")
TASKNUM=$(wc -l "$dest" | sed 's/^[[:space:]]*\([0-9]*\).*/\1/') [ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: '$input' added to $dest on line $TASKNUM."
[[ $VERBOSE = 1 ]] && echo "TODO: '$input' added to $dest on line $TASKNUM."
else else
echo "TODO: Destination file $dest does not exist." echo "TODO: Destination file $dest does not exist."
fi fi
@@ -318,21 +555,17 @@ case $action in
[ -z "$item" ] && die "$errmsg" [ -z "$item" ] && die "$errmsg"
[[ "$item" = +([0-9]) ]] || die "$errmsg" [[ "$item" = +([0-9]) ]] || die "$errmsg"
todo=$(sed "$item!d" "$TODO_FILE") todo=$(sed "$item!d" "$TODO_FILE")
[ -z "$todo" ] && die "$item: No such todo." [ -z "$todo" ] && die "$item: No such todo."
if [[ -z "$1" && $TODOTXT_FORCE = 0 ]]; then
if [[ -z "$1" && $FORCE = 0 ]]; then
echo -n "Append: " echo -n "Append: "
read input read input
else else
input=$* input=$*
fi fi
if sed -i.bak $item" s|^.*|& $input|" "$TODO_FILE"; then if sed -i.bak $item" s|^.*|& $input|" "$TODO_FILE"; then
newtodo=$(sed "$item!d" "$TODO_FILE") newtodo=$(sed "$item!d" "$TODO_FILE")
[[ $VERBOSE = 1 ]] && echo "$item: $newtodo" [ $TODOTXT_VERBOSE -gt 0 ] && echo "$item: $newtodo"
else else
echo "TODO: Error appending task $item." echo "TODO: Error appending task $item."
fi fi
@@ -342,7 +575,7 @@ case $action in
archive;; archive;;
"del" | "rm" ) "del" | "rm" )
# replace deleted line with a blank line when PRESERVE_LINE_NUMBERS is 1 # replace deleted line with a blank line when TODOTXT_PRESERVE_LINE_NUMBERS is 1
errmsg="usage: $0 del ITEM#" errmsg="usage: $0 del ITEM#"
item=$2 item=$2
[ -z "$item" ] && die "$errmsg" [ -z "$item" ] && die "$errmsg"
@@ -353,24 +586,22 @@ case $action in
if sed -ne "$item p" "$TODO_FILE" | grep "^."; then if sed -ne "$item p" "$TODO_FILE" | grep "^."; then
DELETEME=$(sed "$2!d" "$TODO_FILE") DELETEME=$(sed "$2!d" "$TODO_FILE")
if [ $FORCE = 0 ]; then if [ $TODOTXT_FORCE = 0 ]; then
echo "Delete '$DELETEME'? (y/n)" echo "Delete '$DELETEME'? (y/n)"
read ANSWER read ANSWER
else else
ANSWER="y" ANSWER="y"
fi fi
if [ "$ANSWER" = "y" ]; then if [ "$ANSWER" = "y" ]; then
if [ $PRESERVE_LINE_NUMBERS = 0 ]; then if [ $TODOTXT_PRESERVE_LINE_NUMBERS = 0 ]; then
# delete line (changes line numbers) # delete line (changes line numbers)
sed -i.bak -e $2"s/^.*//" -e '/./!d' "$TODO_FILE" sed -i.bak -e $2"s/^.*//" -e '/./!d' "$TODO_FILE"
else else
# leave blank line behind (preserves line numbers) # leave blank line behind (preserves line numbers)
sed -i.bak -e $2"s/^.*//" "$TODO_FILE" sed -i.bak -e $2"s/^.*//" "$TODO_FILE"
fi fi
[[ $VERBOSE = 1 ]] && echo "TODO: '$DELETEME' deleted." [ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: '$DELETEME' deleted."
cleanup cleanup
else else
echo "TODO: No tasks were deleted." echo "TODO: No tasks were deleted."
fi fi
@@ -379,7 +610,7 @@ case $action in
fi fi
else else
sed -i.bak -e $item"s/$3/ /g" "$TODO_FILE" sed -i.bak -e $item"s/$3/ /g" "$TODO_FILE"
[[ $VERBOSE = 1 ]] && echo "TODO: $3 removed from $item." [ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: $3 removed from $item."
fi ;; fi ;;
"depri" | "dp" ) "depri" | "dp" )
@@ -396,8 +627,8 @@ case $action in
#it's all good, continue #it's all good, continue
sed -i.bak -e $2"s/^(.*) //" "$TODO_FILE" sed -i.bak -e $2"s/^(.*) //" "$TODO_FILE"
NEWTODO=$(sed "$2!d" "$TODO_FILE") NEWTODO=$(sed "$2!d" "$TODO_FILE")
[[ $VERBOSE = 1 ]] && echo -e "`echo "$item: $NEWTODO"`" [ $TODOTXT_VERBOSE -gt 0 ] && echo -e "`echo "$item: $NEWTODO"`"
[[ $VERBOSE = 1 ]] && echo "TODO: $item deprioritized." [ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: $item deprioritized."
cleanup cleanup
else else
die "$errmsg" die "$errmsg"
@@ -417,93 +648,43 @@ case $action in
sed -i.bak $item"s/^(.*) //" "$TODO_FILE" sed -i.bak $item"s/^(.*) //" "$TODO_FILE"
sed -i.bak $item"s|^|&x $now |" "$TODO_FILE" sed -i.bak $item"s|^|&x $now |" "$TODO_FILE"
newtodo=$(sed "$item!d" "$TODO_FILE") newtodo=$(sed "$item!d" "$TODO_FILE")
[[ $VERBOSE = 1 ]] && echo "$item: $newtodo" [ $TODOTXT_VERBOSE -gt 0 ] && echo "$item: $newtodo"
[[ $VERBOSE = 1 ]] && echo "TODO: $item marked as done." [ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: $item marked as done."
if [ $AUTO_ARCHIVE = 1 ]; then if [ $TODOTXT_AUTO_ARCHIVE = 1 ]; then
archive archive
fi fi
cleanup ;; cleanup ;;
"help" )
help
;;
"list" | "ls" ) "list" | "ls" )
item=$2 shift ## Was ls; new $1 is first search term
if [ -z "$item" ]; then _list "$TODO_FILE" "$@"
echo -e "`sed = "$TODO_FILE" | sed 'N; s/^/ /; s/ *\(.\{2,\}\)\n/\1 /' | sed 's/^ /0/' | sort -f -k2 | sed '/^[0-9][0-9] x /!s/\(.*(A).*\)/'$PRI_A'\1'$DEFAULT'/g' | sed '/^[0-9][0-9] x /!s/\(.*(B).*\)/'$PRI_B'\1'$DEFAULT'/g' | sed '/^[0-9][0-9] x /!s/\(.*(C).*\)/'$PRI_C'\1'$DEFAULT'/g' | sed '/^[0-9][0-9] x /!s/\(.*([A-Z]).*\)/'$PRI_X'\1'$DEFAULT'/'`"
echo "--"
NUMTASKS=$(wc -l "$TODO_FILE" | sed 's/^[[:space:]]*\([0-9]*\).*/\1/')
echo "TODO: $NUMTASKS tasks in $TODO_FILE."
else
command=`sed = "$TODO_FILE" | sed 'N; s/^/ /; s/ *\(.\{2,\}\)\n/\1 /' | sed 's/^ /0/' | sort -f -k2 | sed '/^[0-9][0-9] x /!s/\(.*(A).*\)/'$PRI_A'\1'$DEFAULT'/g' | sed '/^[0-9][0-9] x /!s/\(.*(B).*\)/'$PRI_B'\1'$DEFAULT'/g' | sed '/^[0-9][0-9] x /!s/\(.*(C).*\)/'$PRI_C'\1'$DEFAULT'/g' | sed '/^[0-9][0-9] x /!s/\(.*([A-Z]).*\)/'$PRI_X'\1'$DEFAULT'/' | grep -i $item `
shift
shift
for i in $*
do
command=`echo "$command" | grep -i $i `
done
command=`echo "$command" | sort -f -k2`
echo -e "$command" cleanup
fi ;;
cleanup ;;
"listall" | "lsa" ) "listall" | "lsa" )
item=$2 shift ## Was lsa; new $1 is first search term
cat "$TODO_FILE" "$DONE_FILE" > "$TMP_FILE" cat "$TODO_FILE" "$DONE_FILE" > "$TMP_FILE"
_list "$TMP_FILE" "$@"
if [ -z "$item" ]; then cleanup
echo -e "`sed = "$TMP_FILE" | sed 'N; s/^/ /; s/ *\(.\{3,\}\)\n/\1 /' | sed 's/^ /00/' | sed 's/^ /0/' | sort -f -k2 | sed '/^[0-9][0-9][0-9] x /!s/\(.*(A).*\)/'$PRI_A'\1'$DEFAULT'/g' | sed '/^[0-9][0-9][0-9] x /!s/\(.*(B).*\)/'$PRI_B'\1'$DEFAULT'/g' | sed '/^[0-9][0-9][0-9] x /!s/\(.*(C).*\)/'$PRI_C'\1'$DEFAULT'/g' | sed '/^[0-9][0-9][0-9] x /!s/\(.*([A-Z]).*\)/'$PRI_X'\1'$DEFAULT'/'`" ;;
else
command=`sed = "$TMP_FILE" | sed 'N; s/^/ /; s/ *\(.\{3,\}\)\n/\1 /' | sed 's/^ /00/' | sed 's/^ /0/' | sort -f -k2 | sed '/^[0-9][0-9][0-9] x /!s/\(.*(A).*\)/'$PRI_A'\1'$DEFAULT'/g' | sed '/^[0-9][0-9][0-9] x /!s/\(.*(B).*\)/'$PRI_B'\1'$DEFAULT'/g' | sed '/^[0-9][0-9][0-9] x /!s/\(.*(C).*\)/'$PRI_C'\1'$DEFAULT'/g' | sed '/^[0-9][0-9][0-9] x /!s/\(.*([A-Z]).*\)/'$PRI_X'\1'$DEFAULT'/' | grep -i $item `
shift
shift
for i in $*
do
command=`echo "$command" | grep -i $i `
done
command=`echo "$command" | sort -f -k2`
echo -e "$command"
fi
cleanup ;;
"listfile" | "lf" ) "listfile" | "lf" )
src="$TODO_DIR/$2" shift ## Was listfile, next $1 is file name
FILE="$1"
shift ## Was filename; next $1 is first search term
if [ -z "$3" ]; then _list "$FILE" "$@"
item=""
else
item=$3
fi
if [ -f "$src" ]; then cleanup
if [ -z "$item" ]; then ;;
echo -e "`sed = "$src" | sed 'N; s/^/ /; s/ *\(.\{2,\}\)\n/\1 /' | sed 's/^ /0/' | sort -f -k2 | sed '/^[0-9][0-9] x /!s/\(.*(A).*\)/'$PRI_A'\1'$DEFAULT'/g' | sed '/^[0-9][0-9] x /!s/\(.*(B).*\)/'$PRI_B'\1'$DEFAULT'/g' | sed '/^[0-9][0-9] x /!s/\(.*(C).*\)/'$PRI_C'\1'$DEFAULT'/g' | sed '/^[0-9][0-9] x /!s/\(.*([A-Z]).*\)/'$PRI_X'\1'$DEFAULT'/'`"
if [ $VERBOSE = 1 ]; then
echo "--"
NUMTASKS=$( sed '/./!d' "$src" | wc -l | sed 's/^[[:space:]]*\([0-9]*\).*/\1/')
echo "TODO: $NUMTASKS lines in $src."
fi
else
command=`sed = "$src" | sed 'N; s/^/ /; s/ *\(.\{2,\}\)\n/\1 /' | sed 's/^ /0/' | sort -f -k2 | sed '/^[0-9][0-9] x /!s/\(.*(A).*\)/'$PRI_A'\1'$DEFAULT'/g' | sed '/^[0-9][0-9] x /!s/\(.*(B).*\)/'$PRI_B'\1'$DEFAULT'/g' | sed '/^[0-9][0-9] x /!s/\(.*(C).*\)/'$PRI_C'\1'$DEFAULT'/g' | sed '/^[0-9][0-9] x /!s/\(.*([A-Z]).*\)/'$PRI_X'\1'$DEFAULT'/' | grep -i $item `
shift
shift
for i in $*
do
command=`echo "$command" | grep -i $i `
done
command=`echo "$command" | sort -f -k2`
echo -e "$command"
fi
else
echo "TODO: File $src does not exist."
fi
cleanup ;;
"listcon" | "lsc" ) "listcon" | "lsc" )
gawk '{for(i = 1; i <= NF; i++) print $i}' "$TODO_FILE" | grep '@' | sort | uniq gawk '{for(i = 1; i <= NF; i++) print $i}' "$TODO_FILE" | grep '@' | sort | uniq
@@ -515,43 +696,32 @@ case $action in
"listpri" | "lsp" ) "listpri" | "lsp" )
pri=$( printf "%s\n" "$2" | tr 'a-z' 'A-Z' ) shift ## was "listpri", new $1 is priority to list
errmsg="usage: $0 listpri PRIORITY if [ "${1:-}" ]
note: PRIORITY must a single letter from A to Z." then
## A priority was specified
if [ -z "$pri" ]; then pri=$( printf "%s\n" "$1" | tr 'a-z' 'A-Z' | grep '^[A-Z]$' ) || {
echo -e "`sed = "$TODO_FILE" | sed 'N; s/^/ /; s/ *\(.\{2,\}\)\n/\1 /' | sed 's/^ /0/' | sort -f -k2 | sed 's/^ /0/' | sort -f -k2 | sed '/^[0-9][0-9] x /!s/\(.*(A).*\)/'$PRI_A'\1'$DEFAULT'/g' | sed '/^[0-9][0-9] x /!s/\(.*(B).*\)/'$PRI_B'\1'$DEFAULT'/g' | sed '/^[0-9][0-9] x /!s/\(.*(C).*\)/'$PRI_C'\1'$DEFAULT'/g' | sed '/^[0-9][0-9] x /!s/\(.*([A-Z]).*\)/'$PRI_X'\1'$DEFAULT'/'`" | grep \([A-Z]\) die "usage: $0 listpri PRIORITY
if [ $VERBOSE = 1 ]; then note: PRIORITY must a single letter from A to Z."
echo "--" }
NUMTASKS=$(grep \([A-Z]\) "$TODO_FILE" | wc -l | sed 's/^[[:space:]]*\([0-9]*\).*/\1/')
echo "TODO: $NUMTASKS prioritized tasks in $TODO_FILE."
fi
else else
[[ "$pri" = +([A-Z]) ]] || die "$errmsg" ## No priority specified; show all priority tasks
pri="[[:upper:]]"
echo -e "`sed = "$TODO_FILE" | sed 'N; s/^/ /; s/ *\(.\{2,\}\)\n/\1 /' | sed 's/^ /0/' | sort -f -k2 | sed 's/^ /0/' | sort -f -k2 | sed '/^[0-9][0-9] x /!s/\(.*(A).*\)/'$PRI_A'\1'$DEFAULT'/g' | sed '/^[0-9][0-9] x /!s/\(.*(B).*\)/'$PRI_B'\1'$DEFAULT'/g' | sed '/^[0-9][0-9] x /!s/\(.*(C).*\)/'$PRI_C'\1'$DEFAULT'/g' | sed '/^[0-9][0-9] x /!s/\(.*([A-Z]).*\)/'$PRI_X'\1'$DEFAULT'/'`" | grep \($pri\)
if [ $VERBOSE = 1 ]; then
echo "--"
NUMTASKS=$(grep \($pri\) "$TODO_FILE" | wc -l | sed 's/^[[:space:]]*\([0-9]*\).*/\1/')
echo "TODO: $NUMTASKS tasks prioritized $pri in $TODO_FILE."
fi fi
pri="($pri)"
fi _list "$TODO_FILE" "$pri"
cleanup;; ;;
"move" | "mv" ) "move" | "mv" )
# replace moved line with a blank line when TODOTXT_PRESERVE_LINE_NUMBERS is 1
# replace moved line with a blank line when PRESERVE_LINE_NUMBERS is 1
errmsg="usage: $0 mv ITEM# DEST [SRC]" errmsg="usage: $0 mv ITEM# DEST [SRC]"
item=$2 item=$2
dest="$TODO_DIR/$3" dest="$TODO_DIR/$3"
src="$TODO_DIR/$4" src="$TODO_DIR/$4"
[ -z "$item" ] && die "$errmsg" [ -z "$item" ] && die "$errmsg"
[ -z "$4" ] && src="$TODO_FILE" [ -z "$4" ] && src="$TODO_FILE"
[ -z "$dest" ] && die "$errmsg" [ -z "$dest" ] && die "$errmsg"
@@ -559,19 +729,16 @@ note: PRIORITY must a single letter from A to Z."
if [ -f "$src" ]; then if [ -f "$src" ]; then
if [ -f "$dest" ]; then if [ -f "$dest" ]; then
if sed -ne "$item p" "$src" | grep "^."; then if sed -ne "$item p" "$src" | grep "^."; then
MOVEME=$(sed "$item!d" "$src") MOVEME=$(sed "$item!d" "$src")
if [ $TODOTXT_FORCE = 0 ]; then
if [ $FORCE = 0 ]; then
echo "Move '$MOVEME' from $src to $dest? (y/n)" echo "Move '$MOVEME' from $src to $dest? (y/n)"
read ANSWER read ANSWER
else else
ANSWER="y" ANSWER="y"
fi fi
if [ "$ANSWER" = "y" ]; then if [ "$ANSWER" = "y" ]; then
if [ $PRESERVE_LINE_NUMBERS = 0 ]; then if [ $TODOTXT_PRESERVE_LINE_NUMBERS = 0 ]; then
# delete line (changes line numbers) # delete line (changes line numbers)
sed -i.bak -e $item"s/^.*//" -e '/./!d' "$src" sed -i.bak -e $item"s/^.*//" -e '/./!d' "$src"
else else
@@ -580,16 +747,14 @@ note: PRIORITY must a single letter from A to Z."
fi fi
echo "$MOVEME" >> "$dest" echo "$MOVEME" >> "$dest"
[[ $VERBOSE = 1 ]] && echo "TODO: '$MOVEME' moved from '$src' to '$dest'." [ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: '$MOVEME' moved from '$src' to '$dest'."
cleanup cleanup
else else
echo "TODO: No tasks moved." echo "TODO: No tasks moved."
fi fi
else else
echo "$item: No such item in $src." echo "$item: No such item in $src."
fi fi
else else
echo "TODO: Destination file $dest does not exist." echo "TODO: Destination file $dest does not exist."
fi fi
@@ -605,11 +770,10 @@ note: PRIORITY must a single letter from A to Z."
[ -z "$item" ] && die "$errmsg" [ -z "$item" ] && die "$errmsg"
[[ "$item" = +([0-9]) ]] || die "$errmsg" [[ "$item" = +([0-9]) ]] || die "$errmsg"
todo=$(sed "$item!d" "$TODO_FILE") todo=$(sed "$item!d" "$TODO_FILE")
[ -z "$todo" ] && die "$item: No such todo." [ -z "$todo" ] && die "$item: No such todo."
if [[ -z "$1" && $FORCE = 0 ]]; then if [[ -z "$1" && $TODOTXT_FORCE = 0 ]]; then
echo -n "Prepend: " echo -n "Prepend: "
read input read input
else else
@@ -618,7 +782,7 @@ note: PRIORITY must a single letter from A to Z."
if sed -i.bak $item" s|^.*|$input &|" "$TODO_FILE"; then if sed -i.bak $item" s|^.*|$input &|" "$TODO_FILE"; then
newtodo=$(sed "$item!d" "$TODO_FILE") newtodo=$(sed "$item!d" "$TODO_FILE")
[[ $VERBOSE = 1 ]] && echo "$item: $newtodo" [ $TODOTXT_VERBOSE -gt 0 ] && echo "$item: $newtodo"
else else
echo "TODO: Error prepending task $item." echo "TODO: Error prepending task $item."
fi fi
@@ -641,8 +805,8 @@ note: PRIORITY must be anywhere from A to Z."
#it's all good, continue #it's all good, continue
sed -i.bak -e $2"s/^(.*) //" -e $2"s/^/($newpri) /" "$TODO_FILE" sed -i.bak -e $2"s/^(.*) //" -e $2"s/^/($newpri) /" "$TODO_FILE"
NEWTODO=$(sed "$2!d" "$TODO_FILE") NEWTODO=$(sed "$2!d" "$TODO_FILE")
[[ $VERBOSE = 1 ]] && echo -e "`echo "$item: $NEWTODO"`" [ $TODOTXT_VERBOSE -gt 0 ] && echo -e "`echo "$item: $NEWTODO"`"
[[ $VERBOSE = 1 ]] && echo "TODO: $item prioritized ($newpri)." [ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: $item prioritized ($newpri)."
cleanup cleanup
else else
die "$errmsg" die "$errmsg"
@@ -658,8 +822,7 @@ note: PRIORITY must be anywhere from A to Z."
todo=$(sed "$item!d" "$TODO_FILE") todo=$(sed "$item!d" "$TODO_FILE")
[ -z "$todo" ] && die "$item: No such todo." [ -z "$todo" ] && die "$item: No such todo."
if [[ -z "$1" && $TODOTXT_FORCE = 0 ]]; then
if [[ -z "$1" && $FORCE = 0 ]]; then
echo -n "Replacement: " echo -n "Replacement: "
read input read input
else else
@@ -667,9 +830,9 @@ note: PRIORITY must be anywhere from A to Z."
fi fi
sed -i.bak $item" s|^.*|$input|" "$TODO_FILE" sed -i.bak $item" s|^.*|$input|" "$TODO_FILE"
[[ $VERBOSE = 1 ]] && NEWTODO=$(head -$item "$TODO_FILE" | tail -1) [ $TODOTXT_VERBOSE -gt 0 ] && NEWTODO=$(head -$item "$TODO_FILE" | tail -1)
[[ $VERBOSE = 1 ]] && echo "replaced with" [ $TODOTXT_VERBOSE -gt 0 ] && echo "replaced with"
[[ $VERBOSE = 1 ]] && echo "$item: $NEWTODO" [ $TODOTXT_VERBOSE -gt 0 ] && echo "$item: $NEWTODO"
cleanup;; cleanup;;
"report" ) "report" )
@@ -677,30 +840,21 @@ note: PRIORITY must be anywhere from A to Z."
sed '/^x /!d' "$TODO_FILE" >> "$DONE_FILE" sed '/^x /!d' "$TODO_FILE" >> "$DONE_FILE"
sed -i.bak '/^x /d' "$TODO_FILE" sed -i.bak '/^x /d' "$TODO_FILE"
NUMLINES=$(wc -l "$TODO_FILE" | sed 's/^[[:space:]]*\([0-9]*\).*/\1/') NUMLINES=$( sed -n '$ =' "$TODO_FILE" )
if [ $NUMLINES = "0" ]; then if [ ${NUMLINES:-0} = "0" ]; then
echo "datetime todos dones" >> "$REPORT_FILE" echo "datetime todos dones" >> "$REPORT_FILE"
fi fi
#now report #now report
TOTAL=$(cat "$TODO_FILE" | wc -l | sed 's/^[ \t]*//') TOTAL=$( sed -n '$ =' "$TODO_FILE" )
TDONE=$(cat "$DONE_FILE" | wc -l | sed 's/^[ \t]*//') TDONE=$( sed -n '$ =' "$DONE_FILE" )
TECHO=$(echo $(date +%Y-%m-%d-%T); echo ' '; echo $TOTAL; echo ' '; TECHO=$(echo $(date +%Y-%m-%d-%T); echo ' '; echo ${TOTAL:-0}; echo ' ';
echo $TDONE) echo ${TDONE:-0})
echo $TECHO >> "$REPORT_FILE" echo $TECHO >> "$REPORT_FILE"
[[ $VERBOSE = 1 ]] && echo "TODO: Report file updated." [ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: Report file updated."
cat "$REPORT_FILE" cat "$REPORT_FILE"
cleanup;; cleanup;;
* ) * )
usage usage
if [ -d "$HOME/.todo.actions.d" ] ;;
then
if [ -x "$HOME/.todo.actions.d/$action" ]
then
CFG_FILE="$CFG_FILE" "$HOME/.todo.actions.d/$action" "$@"
else
usage
fi
else
usage
fi
esac esac