Compare commits

...

30 Commits

Author SHA1 Message Date
Ingo Karkat
dfec12e2a4 ENH: Allow listpri filtering with priority ranges.
So far, the listpri action only supports a single priority. Allowing priority ranges (e.g. todo.sh listpri A-C @work) is a simple but useful enhancement.

Note: The syntax extension only clashes with the [TERM] filtering in a few corner cases, and this can be worked around (e.g. "todo.sh listpri A-Z A-Z" lists all prioritized tasks containing the text A-Z).
2012-01-26 13:17:31 +01:00
Gina Trapani
9e38fa11ee Merge pull request #72 from inkarkat/list-optimization2
Optimization: Put grep -v empty task filter inside sed.
2012-01-24 11:28:53 -08:00
Gina Trapani
309b0f81b0 Merge pull request #71 from inkarkat/deduplicate-and-report
Deduplicate and report
2012-01-24 11:26:43 -08:00
Ingo Karkat
f3fc18af6b Optimization: Put grep -v empty task filter inside sed.
No need to spawn off another process for this; we can do this inside the sed command that joins the task numbers with the task text.

Note: The sed on OS X does not understand the \+ bound, only in the form of + when used with -E. Instead, I chose to fall back to the \{1,\} basic regexp, in the hope that it is very portable, and to avoid introducing extended regexps to the script.
2012-01-23 11:55:15 +01:00
Ingo Karkat
25e6d7ae24 FIX: Adapt deduplicate sed command for OS X.
The sed command of BSD / OS X doesn't like { command } blocks in a single expression. So move the (dynamic) deduplicate sed command(s) to the end, and use a label to access them. This also makes the entire sed script somewhat easier to understand.
2012-01-23 11:05:12 +01:00
Ingo Karkat
880d829e8e Create dedicated test file for report tests. 2012-01-21 14:35:04 +01:00
Ingo Karkat
7e525ee743 ENH: Only add new data to report.
When the last reported values are identical to the current values, do not append the same information (just with a new timestamp) to the report. Instead, just print the last report line.

With this, the report action can be scheduled periodically (e.g. via cron) without artificially inflating the report file.
2012-01-21 14:30:21 +01:00
Ingo Karkat
d46adadb1d Align report order with other actions.
Like "add" or "do", first the object, then (in verbose mode) the status message is printed.
2012-01-21 14:29:11 +01:00
Ingo Karkat
d0205b48a6 Use ISO 8601 timestamp format.
IMO 2012-01-14T14:49 looks better than the messy -*-*-*- of 2012-01-14-14:49, and is more aligned with standards.
2012-01-21 14:27:19 +01:00
Ingo Karkat
7a4d11812d Simplify writing of report line. 2012-01-21 14:27:19 +01:00
Ingo Karkat
ba66f66e86 Only print the added report line, not entire report.
I think this makes much more sense, especially once the report gets very long. (One can always use "cat" to view the entire report.)
2012-01-21 14:27:18 +01:00
Ingo Karkat
88ac3d87e6 Remove inactive broken report header.
This was meant to write a report header on the initial report run, but as it mistakenly used TODO_FILE instead of REPORT_FILE, it was inactive, and also missing in the tests. Let's just remove it; the format is simple, anyway.
2012-01-21 14:16:17 +01:00
Ingo Karkat
1a2af45b4d Pull archive() in-line and delegate via recursive call, also for report.
The report action should delegate to archive; it previously (half) did this via duplicated code (and forgot to defragment empty lines, so the tally could be off, and kept silent about the archiving).

The do action directly invoked archive(); if the user had extended / modified the archive action via an eponymous custom action, it would not run. Therefore, always invoke archive through another call of todo.sh, so that a possible custom action is considered.
2012-01-21 14:12:25 +01:00
Ingo Karkat
6424c4c1a0 Support "preserve line numbers" in deduplicate. 2012-01-21 14:12:25 +01:00
Ingo Karkat
fe5cdcb13a Fix deduplicate for non-printable (and non-ASCII) characters. 2012-01-21 14:12:25 +01:00
Ingo Karkat
bf2ca0ed6a Rework fixed archive deduplication into new deduplicate action.
As per discussion on the mailing list (http://tech.groups.yahoo.com/group/todotxt/message/3775), the automatic deduplication during archiving is unexpected and difficult to enforce in other implementations. Rather, make this a separate (optional) action.
2012-01-21 14:12:25 +01:00
Paul Roub
62d78a0034 explained the sed duplicate-removal pattern 2012-01-21 14:12:25 +01:00
Paul Roub
e33603939b Fix typo in duplicate removal on archive, per discussion at http://tech.groups.yahoo.com/group/todotxt/message/3775 2012-01-21 14:12:24 +01:00
Jean Jordaan
c99543506a Various helptext fixes
* 'Quotes optional.' doesn't make sense for 'addm', because without quotes, 'addm' is 'add'.
* There are no projects that don't start with a +.
* Don't tell people to type uppercase when the software takes care of it.
* Mention actions, mention filtering *out* terms.
* Fix link to wiki in the README
Closes #60
2012-01-20 11:46:30 -08:00
Ingo Karkat
b4aaba8387 Strip trailing whitespace when completing tasks. 2012-01-20 11:23:56 -08:00
Ingo Karkat
493e975199 Remove task date(s) when completing prioritized and done tasks.
Replace the primitive substitutions inside the completion function with a call to sed (instead of calling head), and supply more powerful substitutions there.
2012-01-20 11:23:56 -08:00
Ingo Karkat
fda31ea260 Avoid external TR when replacing , with space.
No need for an external tool, Bash can do a global literal substitution itself.
2012-01-20 11:17:37 -08:00
Ingo Karkat
8744167827 Add HIDE_CUSTOM_SUBSTITUTION for customization and add-ons.
Add-ons or users may want to hide parts of the task text from the output.
Though this can already be solved through TODOTXT_FINAL_FILTER, augmenting the configured value is not trivial, and it introduces another SED command into the already long _list() pipeline. Putting an additional HIDE_CUSTOM_SUBSTITUTION into the existing pipeline has hardly any performance implications, and makes the realization of this use case trivial.
2012-01-20 11:10:30 -08:00
Ingo Karkat
73e28b7225 BUG: SED error when HIDE_..._SUBSTITUTION contains whitespace.
This error only occurs when add-ons override either HIDE_PROJECTS_SUBSTITUTION or HIDE_CONTEXTS_SUBSTITUTION with a pattern that contains whitespace, not with the values used within todo.sh. But correcting the sloppy quoting doesn't hurt, neither.
2012-01-20 11:10:30 -08:00
Ingo Karkat
43bd1b645b Add hint for OR'ing TERMs to help text for ls/list.
The regexp syntax and quoting rules aren't known to many who are not well versed in the Bash shell, and difficult to get right even for people in the know. This question came up just recently on the mailing list, too.
2012-01-20 11:09:10 -08:00
Ingo Karkat
4db4494f03 Cosmetics: Correct double-spacing in help text. 2012-01-20 11:09:10 -08:00
Ingo Karkat
799840b664 Cosmetics: Consistently use "TERM(s)" in help text.
Two places only used "TERM" although multiple are supported. This can be misleading: do one or all have to match?
2012-01-20 11:09:10 -08:00
Ingo Karkat
54f15a7854 ENH: listall doesn't simply use concatenated task lists.
The simplistic "listall" action implementation just uses _list() on the concatenation of active and done task lists. This has the following shortcomings:

- Task numbers shown for archived tasks from done.txt are invalid.
- As the number of done tasks likely greatly outnumbers the number of active tasks, the task number padding is often larger than expected (e.g. 0005 instead of 05).
- Verbose output lists all tasks as originating from TODO, whereas it should differentiate between TODO: and DONE: sources.

The main challenge is to keep processing all tasks through a single pass of _list(), so that there is a single, unified sorting applied to all tasks. A custom AWK script sets all (originally invalid) task numbers from done.txt to "0", meaning "archived task".
The verbose message from _list() is replaced with a custom message that shows the tasks from todo.txt, done.txt, and totals.

Oh, and added tests for the previously untested "listall" action.
2012-01-20 11:07:28 -08:00
Ingo Karkat
17658c852d Reformatting: Lay out _list() file numbering in multi-line.
...like the following complex formatting and filtering steps.
2011-12-23 22:51:13 +01:00
Gina Trapani
f8a6e5f8d6 Merge pull request #59 from inkarkat/bug-pri-no-existence-check
BUG: pri doesn't issue an error when the task does not exist.
2011-12-18 21:50:18 -08:00
11 changed files with 589 additions and 74 deletions

View File

@@ -21,6 +21,7 @@ h2. Quick Links
* Original anemic release by "Gina Trapani":http://ginatrapani.org on 5/11/2006. * 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. * 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 * 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 * "Add-on Directory":https://github.com/ginatrapani/todo.txt-cli/wiki/Todo.sh-Add-on-Directory
https://github.com/ginatrapani/todo.txt-cli/wiki/Creating-and-Installing-Add-ons
* "Changelog":http://wiki.github.com/ginatrapani/todo.txt-cli/todosh-changelog * "Changelog":http://wiki.github.com/ginatrapani/todo.txt-cli/todosh-changelog
* "Known Bugs":http://github.com/ginatrapani/todo.txt-cli/issues * "Known Bugs":http://github.com/ginatrapani/todo.txt-cli/issues

View File

@@ -45,6 +45,8 @@ test_expect_success 'null listpri a' '
cat > expect <<EOF cat > expect <<EOF
-- --
TODO: 0 of 0 tasks shown TODO: 0 of 0 tasks shown
DONE: 0 of 0 tasks shown
total 0 of 0 tasks shown
EOF EOF
test_expect_success 'null lsa' ' test_expect_success 'null lsa' '

View File

@@ -61,6 +61,42 @@ TODO: 0 of 5 tasks shown
TODO: 0 of 5 tasks shown TODO: 0 of 5 tasks shown
EOF EOF
cat > todo.txt <<EOF
(B) smell the uppercase Roses +flowers @outside
(X) clean the house from A-Z
(C) notice the sunflowers
(X) listen to music
buy more records from artists A-Z
EOF
test_todo_session 'listpri filtering priority ranges' <<EOF
>>> todo.sh -p listpri a-c
1 (B) smell the uppercase Roses +flowers @outside
3 (C) notice the sunflowers
--
TODO: 2 of 5 tasks shown
>>> todo.sh -p listpri c-Z
3 (C) notice the sunflowers
2 (X) clean the house from A-Z
4 (X) listen to music
--
TODO: 3 of 5 tasks shown
>>> todo.sh -p listpri A-
2 (X) clean the house from A-Z
--
TODO: 1 of 5 tasks shown
>>> todo.sh -p listpri A-C A-Z
--
TODO: 0 of 5 tasks shown
>>> todo.sh -p listpri X A-Z
2 (X) clean the house from A-Z
--
TODO: 1 of 5 tasks shown
EOF
cat > todo.txt <<EOF cat > todo.txt <<EOF
(B) ccc xxx this line should be third. (B) ccc xxx this line should be third.
ccc xxx this line should be third. ccc xxx this line should be third.

View File

@@ -53,6 +53,18 @@ test_todo_session 'checking TODOTXT_FINAL_FILTER' <<EOF
TODO: 3 of 3 tasks shown TODO: 3 of 3 tasks shown
EOF EOF
#
# check the custom hiding
#
test_todo_session 'checking HIDE_CUSTOM_SUBSTITUTION' <<EOF
>>> HIDE_CUSTOM_SUBSTITUTION='[tT]h' todo.sh ls
2 aaa zzz is line should be first.
3 bbb yyy is line should be second.
1 ccc xxx is line should be ird.
--
TODO: 3 of 3 tasks shown
EOF
# #
# check the filtering of TERM # check the filtering of TERM
# #

150
tests/t1350-listall.sh Executable file
View File

@@ -0,0 +1,150 @@
#!/bin/sh
test_description='listall functionality
'
. ./test-lib.sh
cat > todo.txt <<EOF
smell the uppercase Roses +flowers @outside
x 2011-08-08 tend the garden @outside
notice the sunflowers
x 2011-12-26 go outside +wakeup
(A) stop
EOF
cat > done.txt <<EOF
x 2011-12-01 eat breakfast
x 2011-12-05 smell the coffee +wakeup
EOF
test_todo_session 'basic listall' <<EOF
>>> todo.sh -p listall
5 (A) stop
3 notice the sunflowers
1 smell the uppercase Roses +flowers @outside
2 x 2011-08-08 tend the garden @outside
0 x 2011-12-01 eat breakfast
0 x 2011-12-05 smell the coffee +wakeup
4 x 2011-12-26 go outside +wakeup
--
TODO: 5 of 5 tasks shown
DONE: 2 of 2 tasks shown
total 7 of 7 tasks shown
EOF
test_todo_session 'listall highlighting' <<EOF
>>> todo.sh listall
5 (A) stop
3 notice the sunflowers
1 smell the uppercase Roses +flowers @outside
2 x 2011-08-08 tend the garden @outside
0 x 2011-12-01 eat breakfast
0 x 2011-12-05 smell the coffee +wakeup
4 x 2011-12-26 go outside +wakeup
--
TODO: 5 of 5 tasks shown
DONE: 2 of 2 tasks shown
total 7 of 7 tasks shown
EOF
test_todo_session 'listall nonverbose' <<EOF
>>> TODOTXT_VERBOSE=0 todo.sh -p listall
5 (A) stop
3 notice the sunflowers
1 smell the uppercase Roses +flowers @outside
2 x 2011-08-08 tend the garden @outside
0 x 2011-12-01 eat breakfast
0 x 2011-12-05 smell the coffee +wakeup
4 x 2011-12-26 go outside +wakeup
EOF
test_todo_session 'listall filtering' <<EOF
>>> todo.sh -p listall @outside
1 smell the uppercase Roses +flowers @outside
2 x 2011-08-08 tend the garden @outside
--
TODO: 2 of 5 tasks shown
DONE: 0 of 2 tasks shown
total 2 of 7 tasks shown
>>> todo.sh -p listall the
3 notice the sunflowers
1 smell the uppercase Roses +flowers @outside
2 x 2011-08-08 tend the garden @outside
0 x 2011-12-05 smell the coffee +wakeup
--
TODO: 3 of 5 tasks shown
DONE: 1 of 2 tasks shown
total 4 of 7 tasks shown
>>> todo.sh -p listall breakfast
0 x 2011-12-01 eat breakfast
--
TODO: 0 of 5 tasks shown
DONE: 1 of 2 tasks shown
total 1 of 7 tasks shown
>>> todo.sh -p listall doesnotmatch
--
TODO: 0 of 5 tasks shown
DONE: 0 of 2 tasks shown
total 0 of 7 tasks shown
EOF
cat >> done.txt <<EOF
x 2010-01-01 old task 1
x 2010-01-01 old task 2
x 2010-01-01 old task 3
x 2010-01-01 old task 4
EOF
test_todo_session 'listall number width' <<EOF
>>> todo.sh -p listall
5 (A) stop
3 notice the sunflowers
1 smell the uppercase Roses +flowers @outside
0 x 2010-01-01 old task 1
0 x 2010-01-01 old task 2
0 x 2010-01-01 old task 3
0 x 2010-01-01 old task 4
2 x 2011-08-08 tend the garden @outside
0 x 2011-12-01 eat breakfast
0 x 2011-12-05 smell the coffee +wakeup
4 x 2011-12-26 go outside +wakeup
--
TODO: 5 of 5 tasks shown
DONE: 6 of 6 tasks shown
total 11 of 11 tasks shown
>>> TODOTXT_VERBOSE=0 todo.sh add new task 1
>>> TODOTXT_VERBOSE=0 todo.sh add new task 2
>>> TODOTXT_VERBOSE=0 todo.sh add new task 3
>>> TODOTXT_VERBOSE=0 todo.sh add new task 4
>>> TODOTXT_VERBOSE=0 todo.sh add new task 5
>>> todo.sh -p listall
05 (A) stop
06 new task 1
07 new task 2
08 new task 3
09 new task 4
10 new task 5
03 notice the sunflowers
01 smell the uppercase Roses +flowers @outside
00 x 2010-01-01 old task 1
00 x 2010-01-01 old task 2
00 x 2010-01-01 old task 3
00 x 2010-01-01 old task 4
02 x 2011-08-08 tend the garden @outside
00 x 2011-12-01 eat breakfast
00 x 2011-12-05 smell the coffee +wakeup
04 x 2011-12-26 go outside +wakeup
--
TODO: 10 of 10 tasks shown
DONE: 6 of 6 tasks shown
total 16 of 16 tasks shown
EOF
test_done

35
tests/t1900-archive.sh Executable file
View File

@@ -0,0 +1,35 @@
#!/bin/sh
test_description='archive functionality
Ensure we can archive items successfully.
'
. ./test-lib.sh
cat > todo.txt <<EOF
one
two
three
one
x done
four
EOF
test_todo_session 'archive with duplicates' <<EOF
>>> todo.sh archive
x done
TODO: $HOME/todo.txt archived.
EOF
test_todo_session 'list after archive' <<EOF
>>> todo.sh ls
5 four
1 one
4 one
3 three
2 two
--
TODO: 5 of 5 tasks shown
EOF
test_done

103
tests/t1910-deduplicate.sh Executable file
View File

@@ -0,0 +1,103 @@
#!/bin/sh
test_description='deduplicate functionality
Ensure we can deduplicate items successfully.
'
. ./test-lib.sh
cat > todo.txt <<EOF
duplicated
two
x done
duplicated
double task
double task
three
EOF
test_todo_session 'deduplicate and preserve line numbers' <<EOF
>>> todo.sh deduplicate
TODO: 2 duplicate task(s) removed
>>> todo.sh -p ls
5 double task
1 duplicated
7 three
2 two
3 x done
--
TODO: 5 of 5 tasks shown
EOF
test_todo_session 'deduplicate without duplicates' <<EOF
>>> todo.sh deduplicate
TODO: No duplicate tasks found
EOF
cat > todo.txt <<EOF
duplicated
two
x done
duplicated
double task
double task
three
EOF
test_todo_session 'deduplicate and delete lines' <<EOF
>>> todo.sh -n deduplicate
TODO: 2 duplicate task(s) removed
>>> todo.sh -p ls
4 double task
1 duplicated
5 three
2 two
3 x done
--
TODO: 5 of 5 tasks shown
EOF
cat > todo.txt <<EOF
one
duplicated
three
duplicated
duplicated
six
duplicated
EOF
test_todo_session 'deduplicate more than two occurrences' <<EOF
>>> todo.sh deduplicate
TODO: 3 duplicate task(s) removed
>>> todo.sh -p ls
2 duplicated
1 one
6 six
3 three
--
TODO: 4 of 4 tasks shown
EOF
cat > todo.txt <<EOF
normal task
a bold task
something else
a bold task
something more
EOF
test_todo_session 'deduplicate with non-printable duplicates' <<EOF
>>> todo.sh deduplicate
TODO: 1 duplicate task(s) removed
>>> todo.sh -p ls
2 a bold task
1 normal task
3 something else
5 something more
--
TODO: 4 of 4 tasks shown
EOF
test_done

96
tests/t1950-report.sh Executable file
View File

@@ -0,0 +1,96 @@
#!/bin/sh
test_description='report functionality
This test checks the reporting and the format of the report file.
'
. ./test-lib.sh
cat > todo.txt <<EOF
(B) smell the uppercase Roses +flowers @outside
stop and think
smell the coffee +wakeup
make the coffee +wakeup
visit http://example.com
EOF
test_todo_session 'create new report' <<EOF
>>> todo.sh report
TODO: $HOME/todo.txt archived.
2009-02-13T04:40:00 5 0
TODO: Report file updated.
>>> todo.sh -p list
1 (B) smell the uppercase Roses +flowers @outside
4 make the coffee +wakeup
3 smell the coffee +wakeup
2 stop and think
5 visit http://example.com
--
TODO: 5 of 5 tasks shown
EOF
test_todo_session 'report of done tasks' <<EOF
>>> todo.sh -A do 3
3 x 2009-02-13 smell the coffee +wakeup
TODO: 3 marked as done.
x 2009-02-13 smell the coffee +wakeup
TODO: $HOME/todo.txt archived.
>>> todo.sh report
TODO: $HOME/todo.txt archived.
2009-02-13T04:40:00 4 1
TODO: Report file updated.
>>> todo.sh -p list
1 (B) smell the uppercase Roses +flowers @outside
3 make the coffee +wakeup
2 stop and think
4 visit http://example.com
--
TODO: 4 of 4 tasks shown
EOF
test_todo_session 'report performs archiving' <<EOF
>>> todo.sh -a do 3
3 x 2009-02-13 make the coffee +wakeup
TODO: 3 marked as done.
>>> todo.sh report
x 2009-02-13 make the coffee +wakeup
TODO: $HOME/todo.txt archived.
2009-02-13T04:40:00 3 2
TODO: Report file updated.
>>> todo.sh -p list
1 (B) smell the uppercase Roses +flowers @outside
2 stop and think
3 visit http://example.com
--
TODO: 3 of 3 tasks shown
>>> todo.sh -p listfile done.txt
2 x 2009-02-13 make the coffee +wakeup
1 x 2009-02-13 smell the coffee +wakeup
--
DONE: 2 of 2 tasks shown
EOF
test_todo_session 'report is unchanged when no changes' <<EOF
>>> cat report.txt
2009-02-13T04:40:00 5 0
2009-02-13T04:40:00 4 1
2009-02-13T04:40:00 3 2
>>> todo.sh report
TODO: $HOME/todo.txt archived.
2009-02-13T04:40:00 3 2
TODO: Report file is up-to-date.
>>> cat report.txt
2009-02-13T04:40:00 5 0
2009-02-13T04:40:00 4 1
2009-02-13T04:40:00 3 2
EOF
test_done

View File

@@ -85,13 +85,9 @@ TODO: $HOME/todo.txt archived.
TODO: 5 of 5 tasks shown TODO: 5 of 5 tasks shown
>>> todo.sh report >>> todo.sh report
TODO: $HOME/todo.txt archived.
2009-02-13T04:40:00 5 1
TODO: Report file updated. TODO: Report file updated.
2009-02-13-04:40:00 5 1
>>> todo.sh report
TODO: Report file updated.
2009-02-13-04:40:00 5 1
2009-02-13-04:40:00 5 1
>>> todo.sh append g a >>> todo.sh append g a
usage: todo.sh append ITEM# "TEXT TO APPEND" usage: todo.sh append ITEM# "TEXT TO APPEND"

188
todo.sh
View File

@@ -50,6 +50,7 @@ shorthelp()
append|app ITEM# "TEXT TO APPEND" append|app ITEM# "TEXT TO APPEND"
archive archive
command [ACTIONS] command [ACTIONS]
deduplicate
del|rm ITEM# [TERM] del|rm ITEM# [TERM]
depri|dp ITEM#[, ITEM#, ITEM#, ...] depri|dp ITEM#[, ITEM#, ITEM#, ...]
do ITEM#[, ITEM#, ITEM#, ...] do ITEM#[, ITEM#, ITEM#, ...]
@@ -58,7 +59,7 @@ shorthelp()
listall|lsa [TERM...] listall|lsa [TERM...]
listcon|lsc listcon|lsc
listfile|lf [SRC [TERM...]] listfile|lf [SRC [TERM...]]
listpri|lsp [PRIORITY] [TERM...] listpri|lsp [PRIORITIES] [TERM...]
listproj|lsprj [TERM...] listproj|lsprj [TERM...]
move|mv ITEM# DEST [SRC] move|mv ITEM# DEST [SRC]
prepend|prep ITEM# "TEXT TO PREPEND" prepend|prep ITEM# "TEXT TO PREPEND"
@@ -67,6 +68,8 @@ shorthelp()
report report
shorthelp shorthelp
Actions can be added and overridden using scripts in the actions
directory.
EndHelp EndHelp
# Only list the one-line usage from the add-on actions. This assumes that # Only list the one-line usage from the add-on actions. This assumes that
@@ -87,10 +90,10 @@ help()
Options: Options:
-@ -@
Hide context names in list output. Use twice to show context Hide context names in list output. Use twice to show context
names (default). names (default).
-+ -+
Hide project names in list output. Use twice to show project Hide project names in list output. Use twice to show project
names (default). names (default).
-c -c
Color mode Color mode
@@ -103,7 +106,7 @@ help()
-p -p
Plain mode turns off colors Plain mode turns off colors
-P -P
Hide priority labels in list output. Use twice to show Hide priority labels in list output. Use twice to show
priority labels (default). priority labels (default).
-a -a
Don't auto-archive tasks automatically on completion Don't auto-archive tasks automatically on completion
@@ -162,7 +165,6 @@ help()
Adds FIRST THING I NEED TO DO to your todo.txt on its own line and Adds FIRST THING I NEED TO DO to your todo.txt on its own line and
Adds SECOND THING I NEED TO DO to you todo.txt on its own line. Adds SECOND THING I NEED TO DO to you todo.txt on its own line.
Project and context notation optional. Project and context notation optional.
Quotes optional.
addto DEST "TEXT TO ADD" addto DEST "TEXT TO ADD"
Adds a line of text to any file located in the todo.txt directory. Adds a line of text to any file located in the todo.txt directory.
@@ -180,6 +182,9 @@ help()
Runs the remaining arguments using only todo.sh builtins. Runs the remaining arguments using only todo.sh builtins.
Will not call any .todo.actions.d scripts. Will not call any .todo.actions.d scripts.
deduplicate
Removes duplicate lines from todo.txt.
del ITEM# [TERM] del ITEM# [TERM]
rm ITEM# [TERM] rm ITEM# [TERM]
Deletes the task on line ITEM# in todo.txt. Deletes the task on line ITEM# in todo.txt.
@@ -199,13 +204,19 @@ help()
list [TERM...] list [TERM...]
ls [TERM...] ls [TERM...]
Displays all tasks that contain TERM(s) sorted by priority with line Displays all tasks that contain TERM(s) sorted by priority with line
numbers. If no TERM specified, lists entire todo.txt. numbers. Each task must match all TERM(s) (logical AND); to display
tasks that contain any TERM (logical OR), use
"TERM1\|TERM2\|..." (with quotes), or TERM1\\\|TERM2 (unquoted).
Hides all tasks that contain TERM(s) preceded by a
minus sign (i.e. -TERM). If no TERM specified, lists entire todo.txt.
listall [TERM...] listall [TERM...]
lsa [TERM...] lsa [TERM...]
Displays all the lines in todo.txt AND done.txt that contain TERM(s) 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 sorted by priority with line numbers. Hides all tasks that
entire todo.txt AND done.txt concatenated and sorted. contain TERM(s) preceded by a minus sign (i.e. -TERM). If no
TERM specified, lists entire todo.txt AND done.txt
concatenated and sorted.
listcon listcon
lsc lsc
@@ -215,19 +226,24 @@ help()
lf [SRC [TERM...]] lf [SRC [TERM...]]
Displays all the lines in SRC file located in the todo.txt directory, Displays all the lines in SRC file located in the todo.txt directory,
sorted by priority with line numbers. If TERM specified, lists sorted by priority with line numbers. If TERM specified, lists
all lines that contain TERM in SRC file. all lines that contain TERM(s) in SRC file. Hides all tasks that
contain TERM(s) preceded by a minus sign (i.e. -TERM).
Without any arguments, the names of all text files in the todo.txt Without any arguments, the names of all text files in the todo.txt
directory are listed. directory are listed.
listpri [PRIORITY] [TERM...] listpri [PRIORITIES] [TERM...]
lsp [PRIORITY] [TERM...] lsp [PRIORITIES] [TERM...]
Displays all tasks prioritized PRIORITY. Displays all tasks prioritized PRIORITIES.
If no PRIORITY specified, lists all prioritized tasks. PRIORITIES can be a single one (A) or a range (A-C).
If TERM specified, lists only prioritized tasks that contain TERM. If no PRIORITIES specified, lists all prioritized tasks.
If TERM specified, lists only prioritized tasks that contain TERM(s).
Hides all tasks that contain TERM(s) preceded by a minus sign
(i.e. -TERM).
listproj listproj
lsprj lsprj
Lists all the projects that start with the + sign in todo.txt. Lists all the projects (terms that start with a + sign) in
todo.txt.
move ITEM# DEST [SRC] move ITEM# DEST [SRC]
mv ITEM# DEST [SRC] mv ITEM# DEST [SRC]
@@ -245,7 +261,7 @@ help()
p ITEM# PRIORITY p ITEM# PRIORITY
Adds PRIORITY to task on line ITEM#. If the task is already Adds PRIORITY to task on line ITEM#. If the task is already
prioritized, replaces current priority with new PRIORITY. prioritized, replaces current priority with new PRIORITY.
PRIORITY must be an uppercase letter between A and Z. PRIORITY must be a letter between A and Z.
replace ITEM# "UPDATED TODO" replace ITEM# "UPDATED TODO"
Replaces task on line ITEM# with UPDATED TODO. Replaces task on line ITEM# with UPDATED TODO.
@@ -256,7 +272,6 @@ help()
shorthelp shorthelp
List the one-line usage of all built-in and add-on actions. List the one-line usage of all built-in and add-on actions.
EndActionsHelp EndActionsHelp
addonHelp addonHelp
@@ -353,20 +368,6 @@ getNewtodo()
[ -z "$newtodo" ] && die "$(getPrefix "$2"): No updated task $item." [ -z "$newtodo" ] && die "$(getPrefix "$2"): No updated task $item."
} }
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"
if [ $TODOTXT_VERBOSE -gt 0 ]; then
echo "TODO: $TODO_FILE archived."
fi
}
replaceOrPrepend() replaceOrPrepend()
{ {
action=$1; shift action=$1; shift
@@ -775,8 +776,12 @@ _list() {
fi fi
items=$( items=$(
sed = "$src" \ sed = "$src" \
| sed "N; s/^/ /; s/ *\(.\{$PADDING,\}\)\n/\1 /" \ | sed -e '''
| grep -v "^[ 0-9]\+ *$" N
s/^/ /
s/ *\([ 0-9]\{'"$PADDING"',\}\)\n/\1 /
/^[ 0-9]\{1,\} *$/d
'''
) )
if [ "${filter_command}" ]; then if [ "${filter_command}" ]; then
filtered_items=$(echo -n "$items" | eval "${filter_command}") filtered_items=$(echo -n "$items" | eval "${filter_command}")
@@ -812,8 +817,9 @@ _list() {
} }
''' \ ''' \
| sed ''' | sed '''
s/'${HIDE_PROJECTS_SUBSTITUTION:-^}'//g s/'"${HIDE_PROJECTS_SUBSTITUTION:-^}"'//g
s/'${HIDE_CONTEXTS_SUBSTITUTION:-^}'//g s/'"${HIDE_CONTEXTS_SUBSTITUTION:-^}"'//g
s/'"${HIDE_CUSTOM_SUBSTITUTION:-^}"'//g
''' \ ''' \
| eval ${TODOTXT_FINAL_FILTER} \ | eval ${TODOTXT_FINAL_FILTER} \
) )
@@ -933,7 +939,15 @@ case $action in
;; ;;
"archive" ) "archive" )
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"
if [ $TODOTXT_VERBOSE -gt 0 ]; then
echo "TODO: $TODO_FILE archived."
fi
;;
"del" | "rm" ) "del" | "rm" )
# replace deleted line with a blank line when TODOTXT_PRESERVE_LINE_NUMBERS is 1 # replace deleted line with a blank line when TODOTXT_PRESERVE_LINE_NUMBERS is 1
@@ -991,7 +1005,7 @@ case $action in
# Split multiple depri's, if comma separated change to whitespace separated # Split multiple depri's, if comma separated change to whitespace separated
# Loop the 'depri' function for each item # Loop the 'depri' function for each item
for item in $(echo $* | tr ',' ' '); do for item in ${*//,/ }; do
getTodo "$item" getTodo "$item"
if [[ "$todo" = \(?\)\ * ]]; then if [[ "$todo" = \(?\)\ * ]]; then
@@ -1015,7 +1029,7 @@ case $action in
# Split multiple do's, if comma separated change to whitespace separated # Split multiple do's, if comma separated change to whitespace separated
# Loop the 'do' function for each item # Loop the 'do' function for each item
for item in $(echo $* | tr ',' ' '); do for item in ${*//,/ }; do
getTodo "$item" getTodo "$item"
# Check if this item has already been done # Check if this item has already been done
@@ -1035,7 +1049,9 @@ case $action in
done done
if [ $TODOTXT_AUTO_ARCHIVE = 1 ]; then if [ $TODOTXT_AUTO_ARCHIVE = 1 ]; then
archive # Recursively invoke the script to allow overriding of the archive
# action.
"$TODO_FULL_SH" archive
fi fi
;; ;;
@@ -1068,7 +1084,20 @@ case $action in
shift ## Was lsa; new $1 is first search term 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" "$@" TOTAL=$( sed -n '$ =' "$TODO_FILE" )
post_filter_command="awk -v TOTAL=$TOTAL -v PADDING=${#TOTAL} '{ \$1 = sprintf(\"%\" PADDING \"d\", (\$1 > TOTAL ? 0 : \$1)); print }' "
TODOTXT_VERBOSE=0 _list "$TMP_FILE" "$@"
if [ $TODOTXT_VERBOSE -gt 0 ]; then
TDONE=$( sed -n '$ =' "$DONE_FILE" )
TASKNUM=$(TODOTXT_PLAIN=1 TODOTXT_VERBOSE=0 _list "$TODO_FILE" "$@" | sed -n '$ =')
DONENUM=$(TODOTXT_PLAIN=1 TODOTXT_VERBOSE=0 _list "$DONE_FILE" "$@" | sed -n '$ =')
echo "--"
echo "$(getPrefix "$TODO_FILE"): ${TASKNUM:-0} of ${TOTAL:-0} tasks shown"
echo "$(getPrefix "$DONE_FILE"): ${DONENUM:-0} of ${TDONE:-0} tasks shown"
echo "total $((TASKNUM + DONENUM)) of $((TOTAL + TDONE)) tasks shown"
fi
;; ;;
"listfile" | "lf" ) "listfile" | "lf" )
@@ -1096,8 +1125,8 @@ case $action in
"listpri" | "lsp" ) "listpri" | "lsp" )
shift ## was "listpri", new $1 is priority to list or first TERM shift ## was "listpri", new $1 is priority to list or first TERM
pri=$(printf "%s\n" "$1" | tr 'a-z' 'A-Z' | grep '^[A-Z]$') && shift || pri="[A-Z]" pri=$(printf "%s\n" "$1" | tr 'a-z' 'A-Z' | grep -e '^[A-Z]$' -e '^[A-Z]-[A-Z]$') && shift || pri="A-Z"
post_filter_command="grep '^ *[0-9]\+ (${pri}) '" post_filter_command="grep '^ *[0-9]\+ ([${pri}]) '"
_list "$TODO_FILE" "$@" _list "$TODO_FILE" "$@"
;; ;;
@@ -1187,22 +1216,69 @@ note: PRIORITY must be anywhere from A to Z."
;; ;;
"report" ) "report" )
#archive first # archive first
sed '/^x /!d' "$TODO_FILE" >> "$DONE_FILE" # Recursively invoke the script to allow overriding of the archive
sed -i.bak '/^x /d' "$TODO_FILE" # action.
"$TODO_FULL_SH" archive
NUMLINES=$( sed -n '$ =' "$TODO_FILE" )
if [ ${NUMLINES:-0} = "0" ]; then
echo "datetime todos dones" >> "$REPORT_FILE"
fi
#now report
TOTAL=$( sed -n '$ =' "$TODO_FILE" ) TOTAL=$( sed -n '$ =' "$TODO_FILE" )
TDONE=$( sed -n '$ =' "$DONE_FILE" ) TDONE=$( sed -n '$ =' "$DONE_FILE" )
TECHO=$(echo $(date +%Y-%m-%d-%T); echo ' '; echo ${TOTAL:-0}; echo ' '; NEWDATA="${TOTAL:-0} ${TDONE:-0}"
echo ${TDONE:-0}) LASTREPORT=$(sed -ne '$p' "$REPORT_FILE")
echo $TECHO >> "$REPORT_FILE" LASTDATA=${LASTREPORT#* } # Strip timestamp.
[ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: Report file updated." if [ "$LASTDATA" = "$NEWDATA" ]; then
cat "$REPORT_FILE" echo "$LASTREPORT"
[ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: Report file is up-to-date."
else
NEWREPORT="$(date +%Y-%m-%dT%T) ${NEWDATA}"
echo "${NEWREPORT}" >> "$REPORT_FILE"
echo "${NEWREPORT}"
[ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: Report file updated."
fi
;;
"deduplicate" )
if [ $TODOTXT_PRESERVE_LINE_NUMBERS = 0 ]; then
deduplicateSedCommand='d'
else
deduplicateSedCommand='s/^.*//; p'
fi
# To determine the difference when deduplicated lines are preserved, only
# non-empty lines must be counted.
originalTaskNum=$( sed -e '/./!d' "$TODO_FILE" | sed -n '$ =' )
# Look for duplicate lines and discard the second occurrence.
# We start with an empty hold space on the first line. For each line:
# G - appends newline + hold space to the pattern space
# s/\n/&&/; - double up the first new line so we catch adjacent dups
# /^\([^\n]*\n\).*\n\1/b dedup
# If the first line of the hold space shows up again later as an
# entire line, it's a duplicate. Jump to the "dedup" label, where
# either of the following is executed, depending on whether empty
# lines should be preserved:
# d - Delete the current pattern space, quit this line and
# move on to the next, or:
# s/^.*//; p - Clear the task text, print this line and move on to
# the next.
# s/\n//; - else (no duplicate), drop the doubled newline
# h; - replace the hold space with the expanded pattern space
# P; - print up to the first newline (that is, the input line)
# b - end processing of the current line
sed -i.bak -n \
-e 'G; s/\n/&&/; /^\([^\n]*\n\).*\n\1/b dedup' \
-e 's/\n//; h; P; b' \
-e ':dedup' \
-e "$deduplicateSedCommand" \
"$TODO_FILE"
newTaskNum=$( sed -e '/./!d' "$TODO_FILE" | sed -n '$ =' )
deduplicateNum=$(( originalTaskNum - newTaskNum ))
if [ $deduplicateNum -eq 0 ]; then
echo "TODO: No duplicate tasks found"
else
echo "TODO: $deduplicateNum duplicate task(s) removed"
fi
;; ;;
* ) * )

View File

@@ -38,20 +38,28 @@ _todo()
+*) completions=$(TODOTXT_VERBOSE=0 todo.sh command listproj);; +*) completions=$(TODOTXT_VERBOSE=0 todo.sh command listproj);;
@*) completions=$(TODOTXT_VERBOSE=0 todo.sh command listcon);; @*) completions=$(TODOTXT_VERBOSE=0 todo.sh command listcon);;
*) if [[ "$cur" =~ ^[0-9]+$ ]]; then *) if [[ "$cur" =~ ^[0-9]+$ ]]; then
local item=$(TODOTXT_VERBOSE=0 todo.sh -@ -+ -p -x command ls "^ *${cur} " | head -n 1)
# Remove the (padded) task number; we prepend the # Remove the (padded) task number; we prepend the
# user-provided $cur. # user-provided $cur instead.
item=${item#* } # Remove the timestamp prepended by the -t option,
# and the done date (for done tasks); there's no
# Remove the timestamp prepended by the -t option; # todo.txt option for that yet.
# there's no todo.txt option for that yet. # But keep priority and "x"; they're short and may
item=${item#[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] } # provide useful context.
# Remove any trailing whitespace; the Bash
# completion inserts a trailing space itself.
# Finally, limit the output to a single line just as
# a safety check of the ls action output.
local todo=$( \
TODOTXT_VERBOSE=0 todo.sh -@ -+ -p -x command ls "^ *${cur} " | \
sed -e 's/^ *[0-9]\+ //' -e 's/\((.) \)[0-9]\{2,4\}-[0-9]\{2\}-[0-9]\{2\} /\1/' \
-e 's/\([xX] \)\([0-9]\{2,4\}-[0-9]\{2\}-[0-9]\{2\} \)\{1,2\}/\1/' \
-e 's/[[:space:]]*$//' \
-e '1q' \
)
# Append task text as a shell comment. This # Append task text as a shell comment. This
# completion can be a safety check before a # completion can be a safety check before a
# destructive todo.txt operation. # destructive todo.txt operation.
[ "$item" ] && COMPREPLY[0]="$cur # $item" [ "$todo" ] && COMPREPLY[0]="$cur # $todo"
return 0 return 0
else else
return 0 return 0