Compare commits

..

3 Commits

Author SHA1 Message Date
Ingo Karkat
a0f39480bf FIX: Handle special shell characters when filtering TERM.
The double quotes used in the filter_command erroneously expand $VARIABLE, and due to missing quoting in the eval() of filter_command, multiple spaces are condensed into a single space.
Introduce a new function shellquote() to correctly quote each filter TERM.
2011-11-03 18:02:21 +01:00
Ingo Karkat
d804a78fa1 Implement listproj with factored out filtercommand() function.
_list() is way too large and monolithic for many (re-)use cases. As a first step, factor out the building of the filter_command and reuse that for the listproj filtering.
Enhance the listproj test with special cases that show the problems with the previous implementation directly using _list: Option -+, custom final filters, and non-ANSI colors cause it to break.
2011-11-03 16:58:02 +01:00
jmoore
84880ba525 Accept filters for lsprj 2011-11-03 11:03:54 +01:00
7 changed files with 148 additions and 361 deletions

View File

@@ -13,7 +13,7 @@ VERSION-FILE: .FORCE-VERSION-FILE
todo.sh: VERSION-FILE
# For packaging
DISTFILES := todo.cfg todo_completion
DISTFILES := todo.cfg
DISTNAME=todo.txt_cli-$(VERSION)
dist: $(DISTFILES) todo.sh

View File

@@ -39,24 +39,6 @@ GARDEN: 2 added.
GARDEN: 2 of 2 tasks shown
EOF
#
# List available files
#
test_todo_session 'list available files' <<EOF
>>> todo.sh listfile
Files in the todo.txt directory:
done.txt
garden.txt
report.txt
todo.txt
>>> TODOTXT_VERBOSE=0 todo.sh listfile
done.txt
garden.txt
report.txt
todo.txt
EOF
#
# Filter
#

View File

@@ -66,12 +66,6 @@ TODO: 4 added.
TODO: 4 of 4 tasks shown
EOF
test_todo_session 'priority error' <<EOF
>>> todo.sh pri 10 B
=== 1
TODO: No task 10.
EOF
cat > todo.txt <<EOF
(B) smell the uppercase Roses +flowers @outside
(C) notice the sunflowers

View File

@@ -73,29 +73,6 @@ TODO: 1 of 3 tasks shown
TODO: 1 of 3 tasks shown
EOF
#
# check negative filtering via -TERM
#
test_todo_session 'checking negative filtering via -TERM' <<EOF
>>> todo.sh ls -second
2 aaa zzz this line should be first.
1 ccc xxx this line should be third.
--
TODO: 2 of 3 tasks shown
>>> todo.sh ls "-should be f"
3 bbb yyy this line should be second.
1 ccc xxx this line should be third.
--
TODO: 2 of 3 tasks shown
>>> todo.sh ls "- zzz"
3 bbb yyy this line should be second.
1 ccc xxx this line should be third.
--
TODO: 2 of 3 tasks shown
EOF
#
# check the filtering of TERM with regexp
#
@@ -199,7 +176,7 @@ cat > todo.txt <<EOF
(D) @con02 +prj03 -- Some project 03 task, pri D
(D) @con02 +prj04 -- Some project 04 task, pri D
@con01 +prj01 -- Some project 01 task, no priority
@con01 +prj02 -- Some project(S) 02 task, no priority
@con01 +prj02 -- Some project 02 task, no priority
@con02 +prj03 -- Some project 03 task, no priorty
@con02 +prj04 -- Some project 04 task, no priority
EOF
@@ -222,7 +199,7 @@ test_todo_session 'plain mode option' <<EOF
15 (D) @con02 +prj03 -- Some project 03 task, pri D
16 (D) @con02 +prj04 -- Some project 04 task, pri D
17 @con01 +prj01 -- Some project 01 task, no priority
18 @con01 +prj02 -- Some project(S) 02 task, no priority
18 @con01 +prj02 -- Some project 02 task, no priority
19 @con02 +prj03 -- Some project 03 task, no priorty
20 @con02 +prj04 -- Some project 04 task, no priority
--
@@ -246,7 +223,7 @@ TODO: 20 of 20 tasks shown
15 (D) @con02 +prj03 -- Some project 03 task, pri D
16 (D) @con02 +prj04 -- Some project 04 task, pri D
17 @con01 +prj01 -- Some project 01 task, no priority
18 @con01 +prj02 -- Some project(S) 02 task, no priority
18 @con01 +prj02 -- Some project 02 task, no priority
19 @con02 +prj03 -- Some project 03 task, no priorty
20 @con02 +prj04 -- Some project 04 task, no priority
--
@@ -274,7 +251,7 @@ cat > todo.txt <<EOF
(D) @con02 +prj03 -- Some project 03 task, pri D
(D) @con02 +prj04 -- Some project 04 task, pri D
@con01 +prj01 -- Some project 01 task, no priority
@con01 +prj02 -- Some project(S) 02 task, no priority
@con01 +prj02 -- Some project 02 task, no priority
@con02 +prj03 -- Some project 03 task, no priorty
@con02 +prj04 -- Some project 04 task, no priority
EOF
@@ -297,7 +274,7 @@ test_todo_session 'context, project, and priority suppression' <<EOF
15 (D) @con02 +prj03 -- Some project 03 task, pri D
16 (D) @con02 +prj04 -- Some project 04 task, pri D
17 @con01 +prj01 -- Some project 01 task, no priority
18 @con01 +prj02 -- Some project(S) 02 task, no priority
18 @con01 +prj02 -- Some project 02 task, no priority
19 @con02 +prj03 -- Some project 03 task, no priorty
20 @con02 +prj04 -- Some project 04 task, no priority
--
@@ -313,7 +290,7 @@ TODO: 20 of 20 tasks shown
13 (D) @con01 +prj01 -- Some project 01 task, pri D
14 (D) @con01 +prj02 -- Some project 02 task, pri D
17 @con01 +prj01 -- Some project 01 task, no priority
18 @con01 +prj02 -- Some project(S) 02 task, no priority
18 @con01 +prj02 -- Some project 02 task, no priority
--
TODO: 10 of 20 tasks shown
@@ -327,7 +304,7 @@ TODO: 10 of 20 tasks shown
13 @con01 +prj01 -- Some project 01 task, pri D
14 @con01 +prj02 -- Some project 02 task, pri D
17 @con01 +prj01 -- Some project 01 task, no priority
18 @con01 +prj02 -- Some project(S) 02 task, no priority
18 @con01 +prj02 -- Some project 02 task, no priority
--
TODO: 10 of 20 tasks shown
@@ -341,7 +318,7 @@ TODO: 10 of 20 tasks shown
13 (D) @con01 -- Some project 01 task, pri D
14 (D) @con01 -- Some project 02 task, pri D
17 @con01 -- Some project 01 task, no priority
18 @con01 -- Some project(S) 02 task, no priority
18 @con01 -- Some project 02 task, no priority
--
TODO: 10 of 20 tasks shown
@@ -355,7 +332,7 @@ TODO: 10 of 20 tasks shown
13 (D) +prj01 -- Some project 01 task, pri D
14 (D) +prj02 -- Some project 02 task, pri D
17 +prj01 -- Some project 01 task, no priority
18 +prj02 -- Some project(S) 02 task, no priority
18 +prj02 -- Some project 02 task, no priority
--
TODO: 10 of 20 tasks shown
@@ -369,7 +346,7 @@ TODO: 10 of 20 tasks shown
13 +prj01 -- Some project 01 task, pri D
14 +prj02 -- Some project 02 task, pri D
17 +prj01 -- Some project 01 task, no priority
18 +prj02 -- Some project(S) 02 task, no priority
18 +prj02 -- Some project 02 task, no priority
--
TODO: 10 of 20 tasks shown
@@ -383,7 +360,7 @@ TODO: 10 of 20 tasks shown
13 (D) @con01 +prj01 -- Some project 01 task, pri D
14 (D) @con01 +prj02 -- Some project 02 task, pri D
17 @con01 +prj01 -- Some project 01 task, no priority
18 @con01 +prj02 -- Some project(S) 02 task, no priority
18 @con01 +prj02 -- Some project 02 task, no priority
--
TODO: 10 of 20 tasks shown
@@ -397,7 +374,7 @@ TODO: 10 of 20 tasks shown
13 -- Some project 01 task, pri D
14 -- Some project 02 task, pri D
17 -- Some project 01 task, no priority
18 -- Some project(S) 02 task, no priority
18 -- Some project 02 task, no priority
--
TODO: 10 of 20 tasks shown
EOF

View File

@@ -166,20 +166,4 @@ test_todo_session 'highlighting with hidden contexts/projects' <<EOF
TODO: 4 of 4 tasks shown
EOF
# check that priorities are only matched at the start of the task
#
cat > todo.txt <<EOF
(D) some prioritized task
not prioritized
should not be seen as PRIORITIZE(D) task
EOF
test_todo_session 'highlighting priority position' <<EOF
>>> todo.sh ls
1 (D) some prioritized task
2 not prioritized
3 should not be seen as PRIORITIZE(D) task
--
TODO: 3 of 3 tasks shown
EOF
test_done

341
todo.sh
View File

@@ -44,20 +44,20 @@ shorthelp()
Actions:
add|a "THING I NEED TO DO +project @context"
addto DEST "TEXT TO ADD"
addm "THINGS I NEED TO DO
MORE THINGS I NEED TO DO"
addto DEST "TEXT TO ADD"
append|app ITEM# "TEXT TO APPEND"
archive
command [ACTIONS]
del|rm ITEM# [TERM]
depri|dp ITEM#[, ITEM#, ITEM#, ...]
dp|depri ITEM#[, ITEM#, ITEM#, ...]
do ITEM#[, ITEM#, ITEM#, ...]
help
list|ls [TERM...]
listall|lsa [TERM...]
listcon|lsc
listfile|lf [SRC [TERM...]]
listfile|lf SRC [TERM...]
listpri|lsp [PRIORITY] [TERM...]
listproj|lsprj [TERM...]
move|mv ITEM# DEST [SRC]
@@ -65,92 +65,18 @@ shorthelp()
pri|p ITEM# PRIORITY
replace ITEM# "UPDATED TODO"
report
shorthelp
EndHelp
# Only list the one-line usage from the add-on actions. This assumes that
# add-ons use the same usage indentation structure as todo.sh.
addonHelp | grep -e '^ Add-on Actions:' -e '^ [[:alpha:]]'
cat <<-EndHelpFooter
See "help" for more details.
EndHelpFooter
EndHelp
exit 0
}
help()
{
cat <<-EndOptionsHelp
cat <<-EndHelp
Usage: $oneline_usage
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).
-c
Color mode
-d CONFIG_FILE
Use a configuration file other than the default ~/.todo/config
-f
Forces actions without confirmation or interactive input
-h
Display a short help message; same as action "shorthelp"
-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
-A
Auto-archive tasks automatically on completion
-n
Don't preserve line numbers; automatically remove blank lines
on task deletion
-N
Preserve line numbers
-t
Prepend the current date to a task automatically
when it's added.
-T
Do not 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 and
additional help text
-V
Displays version, license and credits
-x
Disables TODOTXT_FINAL_FILTER
EndOptionsHelp
[ $TODOTXT_VERBOSE -gt 1 ] && cat <<-EndVerboseHelp
Environment variables:
TODOTXT_AUTO_ARCHIVE is same as option -a (0)/-A (1)
TODOTXT_CFG_FILE=CONFIG_FILE is same as option -d CONFIG_FILE
TODOTXT_FORCE=1 is same as option -f
TODOTXT_PRESERVE_LINE_NUMBERS is same as option -n (0)/-N (1)
TODOTXT_PLAIN is same as option -p (1)/-c (0)
TODOTXT_DATE_ON_ADD is same as option -t (1)/-T (0)
TODOTXT_VERBOSE=1 is same as option -v
TODOTXT_DISABLE_FILTER=1 is same as option -x
TODOTXT_DEFAULT_ACTION="" run this when called with no arguments
TODOTXT_SORT_COMMAND="sort ..." customize list output
TODOTXT_FINAL_FILTER="sed ..." customize list after color, P@+ hiding
EndVerboseHelp
cat <<-EndActionsHelp
Built-in Actions:
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.
@@ -211,13 +137,11 @@ help()
lsc
Lists all the task contexts that start with the @ sign in todo.txt.
listfile [SRC [TERM...]]
lf [SRC [TERM...]]
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.
Without any arguments, the names of all text files in the todo.txt
directory are listed.
listpri [PRIORITY] [TERM...]
lsp [PRIORITY] [TERM...]
@@ -253,33 +177,81 @@ help()
report
Adds the number of open tasks and done tasks to report.txt.
shorthelp
List the one-line usage of all built-in and add-on actions.
EndActionsHelp
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).
-c
Color mode
-d CONFIG_FILE
Use a configuration file other than the default ~/.todo/config
-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
-A
Auto-archive tasks automatically on completion
-n
Don't preserve line numbers; automatically remove blank lines
on task deletion
-N
Preserve line numbers
-t
Prepend the current date to a task automatically
when it's added.
-T
Do not 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
-x
Disables TODOTXT_FINAL_FILTER
addonHelp
exit 1
}
addonHelp()
{
if [ -d "$TODO_ACTIONS_DIR" ]; then
didPrintAddonActionsHeader=
Environment variables:
TODOTXT_AUTO_ARCHIVE is same as option -a (0)/-A (1)
TODOTXT_CFG_FILE=CONFIG_FILE is same as option -d CONFIG_FILE
TODOTXT_FORCE=1 is same as option -f
TODOTXT_PRESERVE_LINE_NUMBERS is same as option -n (0)/-N (1)
TODOTXT_PLAIN is same as option -p (1)/-c (0)
TODOTXT_DATE_ON_ADD is same as option -t (1)/-T (0)
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
TODOTXT_FINAL_FILTER="sed ..." customize list after color, P@+ hiding
EndHelp
if [ -d "$TODO_ACTIONS_DIR" ]
then
echo ""
for action in "$TODO_ACTIONS_DIR"/*
do
if [ -f "$action" -a -x "$action" ]; then
if [ ! "$didPrintAddonActionsHeader" ]; then
cat <<-EndAddonActionsHeader
Add-on Actions:
EndAddonActionsHeader
didPrintAddonActionsHeader=1
fi
if [ -f "$action" -a -x "$action" ]
then
"$action" usage
fi
done
echo ""
fi
exit 1
}
die()
@@ -296,11 +268,6 @@ cleanup()
cleaninput()
{
# Parameters: When $1 = "for sed", performs additional escaping for use
# in sed substitution with "|" separators.
# Precondition: $input contains text to be cleaned.
# Postcondition: Modifies $input.
# Replace CR and LF with space; tasks always comprise a single line.
input=${input//$'\r'/ }
input=${input//$'\n'/ }
@@ -315,44 +282,6 @@ cleaninput()
fi
}
getPrefix()
{
# Parameters: $1: todo file; empty means $TODO_FILE.
# Returns: Uppercase FILE prefix to be used in place of "TODO:" where
# a different todo file can be specified.
local base=$(basename "${1:-$TODO_FILE}")
echo "${base%%.[^.]*}" | tr 'a-z' 'A-Z'
}
getTodo()
{
# Parameters: $1: task number
# $2: Optional todo file
# Precondition: $errmsg contains usage message.
# Postcondition: $todo contains task text.
local item=$1
[ -z "$item" ] && die "$errmsg"
[ "${item//[0-9]/}" ] && die "$errmsg"
todo=$(sed "$item!d" "${2:-$TODO_FILE}")
[ -z "$todo" ] && die "$(getPrefix "$2"): No task $item."
}
getNewtodo()
{
# Parameters: $1: task number
# $2: Optional todo file
# Precondition: None.
# Postcondition: $newtodo contains task text.
local item=$1
[ -z "$item" ] && die 'Programming error: $item should exist.'
[ "${item//[0-9]/}" ] && die 'Programming error: $item should be numeric.'
newtodo=$(sed "$item!d" "${2:-$TODO_FILE}")
[ -z "$newtodo" ] && die "$(getPrefix "$2"): No updated task $item."
}
archive()
{
#defragment blank lines
@@ -381,7 +310,12 @@ replaceOrPrepend()
;;
esac
shift; item=$1; shift
getTodo "$item"
[ -z "$item" ] && die "$errmsg"
[[ "$item" = +([0-9]) ]] || die "$errmsg"
todo=$(sed "$item!d" "$TODO_FILE")
[ -z "$todo" ] && die "TODO: No task $item."
if [[ -z "$1" && $TODOTXT_FORCE = 0 ]]; then
echo -n "$querytext"
@@ -406,7 +340,7 @@ replaceOrPrepend()
# date again.
sed -i.bak -e "$item s/^${priority}${prepdate}//" -e "$item s|^.*|${priority}${prepdate}${input}${backref}|" "$TODO_FILE"
if [ $TODOTXT_VERBOSE -gt 0 ]; then
getNewtodo "$item"
newtodo=$(sed "$item!d" "$TODO_FILE")
case "$action" in
replace)
echo "$item $todo"
@@ -484,10 +418,7 @@ do
OVR_TODOTXT_FORCE=1
;;
h )
# Short-circuit option parsing and forward to the action.
# Cannot just invoke shorthelp() because we need the configuration
# processed to locate the add-on actions directory.
set -- '-h' 'shorthelp'
shorthelp
;;
n )
OVR_TODOTXT_PRESERVE_LINE_NUMBERS=0
@@ -543,7 +474,6 @@ 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}
TODOTXT_DISABLE_FILTER=${TODOTXT_DISABLE_FILTER:-}
TODOTXT_FINAL_FILTER=${TODOTXT_FINAL_FILTER:-cat}
# Export all TODOTXT_* variables
@@ -696,8 +626,10 @@ _addto() {
echo "$input" >> "$file"
if [ $TODOTXT_VERBOSE -gt 0 ]; then
TASKNUM=$(sed -n '$ =' "$file")
BASE=$(basename "$file")
PREFIX=$(echo ${BASE%%.[^.]*} | tr 'a-z' 'A-Z')
echo "$TASKNUM $input"
echo "$(getPrefix "$file"): $TASKNUM added."
echo "${PREFIX}: $TASKNUM added."
fi
}
@@ -726,7 +658,7 @@ filtercommand()
## $search_term
#
## Remove the first character (-) before adding to our filter command
filter="${filter:-}${filter:+ | }grep -v -i $(shellquote "${search_term:1}")"
filter="${filter:-}${filter:+ | }grep -v -i '$(shellquote "${search_term:1}")'"
fi
done
@@ -800,18 +732,17 @@ _list() {
return color
}
{
pos = match($0, /\([A-Z]\)/)
if (match($0, /^[0-9]+ x /)) {
print highlight("COLOR_DONE") $0 highlight("DEFAULT")
} else if (match($0, /^[0-9]+ \([A-Z]\)[[:space:]]/)) {
clr = highlight("PRI_" substr($0, RSTART + RLENGTH - 3, 1))
print \
(clr ? clr : highlight("PRI_X")) \
(ENVIRON["HIDE_PRIORITY_SUBSTITUTION"] == "" ? $0 : substr($0, 1, RLENGTH - 4) substr($0, RSTART + RLENGTH)) \
highlight("DEFAULT")
} else if (pos > 0) {
clr = highlight("PRI_" substr($0, pos+1, 1))
print ( clr ? clr : highlight("PRI_X") ) $0 highlight("DEFAULT")
} else { print }
}
''' \
| sed '''
s/'${HIDE_PRIORITY_SUBSTITUTION:-^}'//g
s/'${HIDE_PROJECTS_SUBSTITUTION:-^}'//g
s/'${HIDE_CONTEXTS_SUBSTITUTION:-^}'//g
''' \
@@ -820,18 +751,20 @@ _list() {
[ "$filtered_items" ] && echo "$filtered_items"
if [ $TODOTXT_VERBOSE -gt 0 ]; then
BASE=$(basename "$FILE")
PREFIX=$(echo ${BASE%%.[^.]*} | tr 'a-z' 'A-Z')
NUMTASKS=$( echo -n "$filtered_items" | sed -n '$ =' )
TOTALTASKS=$( echo -n "$items" | sed -n '$ =' )
echo "--"
echo "$(getPrefix "$FILE"): ${NUMTASKS:-0} of ${TOTALTASKS:-0} tasks shown"
echo "${PREFIX}: ${NUMTASKS:-0} of ${TOTALTASKS:-0} tasks shown"
fi
if [ $TODOTXT_VERBOSE -gt 1 ]; then
echo "TODO DEBUG: Filter Command was: ${filter_command:-cat}"
fi
}
export -f cleaninput getPrefix getTodo getNewtodo shellquote filtercommand _list die
export -f cleaninput shellquote filtercommand _list die
# == HANDLE ACTION ==
action=$( printf "%s\n" "$ACTION" | tr 'A-Z' 'a-z' )
@@ -908,8 +841,11 @@ case $action in
"append" | "app" )
errmsg="usage: $TODO_SH append ITEM# \"TEXT TO APPEND\""
shift; item=$1; shift
getTodo "$item"
[ -z "$item" ] && die "$errmsg"
[[ "$item" = +([0-9]) ]] || die "$errmsg"
todo=$(sed "$item!d" "$TODO_FILE")
[ -z "$todo" ] && die "TODO: No task $item."
if [[ -z "$1" && $TODOTXT_FORCE = 0 ]]; then
echo -n "Append: "
read input
@@ -924,7 +860,7 @@ case $action in
if sed -i.bak $item" s|^.*|&${appendspace}${input}|" "$TODO_FILE"; then
if [ $TODOTXT_VERBOSE -gt 0 ]; then
getNewtodo "$item"
newtodo=$(sed "$item!d" "$TODO_FILE")
echo "$item $newtodo"
fi
else
@@ -939,11 +875,14 @@ case $action in
# replace deleted line with a blank line when TODOTXT_PRESERVE_LINE_NUMBERS is 1
errmsg="usage: $TODO_SH del ITEM# [TERM]"
item=$2
getTodo "$item"
[ -z "$item" ] && die "$errmsg"
[[ "$item" = +([0-9]) ]] || die "$errmsg"
DELETEME=$(sed "$item!d" "$TODO_FILE")
[ -z "$DELETEME" ] && die "TODO: No task $item."
if [ -z "$3" ]; then
if [ $TODOTXT_FORCE = 0 ]; then
echo "Delete '$todo'? (y/n)"
echo "Delete '$DELETEME'? (y/n)"
read ANSWER
else
ANSWER="y"
@@ -957,7 +896,7 @@ case $action in
sed -i.bak -e $item"s/^.*//" "$TODO_FILE"
fi
if [ $TODOTXT_VERBOSE -gt 0 ]; then
echo "$item $todo"
echo "$item $DELETEME"
echo "TODO: $item deleted."
fi
else
@@ -971,13 +910,13 @@ case $action in
-e $item"s/ *$3 */ /g" \
-e $item"s/$3//g" \
"$TODO_FILE"
getNewtodo "$item"
if [ "$todo" = "$newtodo" ]; then
[ $TODOTXT_VERBOSE -gt 0 ] && echo "$item $todo"
newtodo=$(sed "$item!d" "$TODO_FILE")
if [ "$DELETEME" = "$newtodo" ]; then
[ $TODOTXT_VERBOSE -gt 0 ] && echo "$item $DELETEME"
die "TODO: '$3' not found; no removal done."
fi
if [ $TODOTXT_VERBOSE -gt 0 ]; then
echo "$item $todo"
echo "$item $DELETEME"
echo "TODO: Removed '$3' from task."
echo "$item $newtodo"
fi
@@ -992,13 +931,15 @@ case $action in
# Split multiple depri's, if comma separated change to whitespace separated
# Loop the 'depri' function for each item
for item in $(echo $* | tr ',' ' '); do
getTodo "$item"
[[ "$item" = +([0-9]) ]] || die "$errmsg"
todo=$(sed "$item!d" "$TODO_FILE")
[ -z "$todo" ] && die "TODO: No task $item."
if [[ "$todo" = \(?\)\ * ]]; then
sed -i.bak -e $item"s/^(.) //" "$TODO_FILE"
if [ $TODOTXT_VERBOSE -gt 0 ]; then
getNewtodo "$item"
echo "$item $newtodo"
NEWTODO=$(sed "$item!d" "$TODO_FILE")
echo "$item $NEWTODO"
echo "TODO: $item deprioritized."
fi
else
@@ -1016,7 +957,11 @@ case $action in
# Split multiple do's, if comma separated change to whitespace separated
# Loop the 'do' function for each item
for item in $(echo $* | tr ',' ' '); do
getTodo "$item"
[ -z "$item" ] && die "$errmsg"
[[ "$item" = +([0-9]) ]] || die "$errmsg"
todo=$(sed "$item!d" "$TODO_FILE")
[ -z "$todo" ] && die "TODO: No task $item."
# Check if this item has already been done
if [ "${todo:0:2}" != "x " ]; then
@@ -1025,7 +970,7 @@ case $action in
sed -i.bak $item"s/^(.) //" "$TODO_FILE"
sed -i.bak $item"s|^|x $now |" "$TODO_FILE"
if [ $TODOTXT_VERBOSE -gt 0 ]; then
getNewtodo "$item"
newtodo=$(sed "$item!d" "$TODO_FILE")
echo "$item $newtodo"
echo "TODO: $item marked as done."
fi
@@ -1049,16 +994,6 @@ case $action in
help # just in case something failed above, we go ahead and just spew to STDOUT
;;
"shorthelp" )
if [ -t 1 ] ; then # STDOUT is a TTY
if which "${PAGER:-less}" >/dev/null 2>&1; then
# we have a working PAGER (or less as a default)
shorthelp | "${PAGER:-less}" && exit 0
fi
fi
shorthelp # just in case something failed above, we go ahead and just spew to STDOUT
;;
"list" | "ls" )
shift ## Was ls; new $1 is first search term
_list "$TODO_FILE" "$@"
@@ -1073,15 +1008,10 @@ case $action in
"listfile" | "lf" )
shift ## Was listfile, next $1 is file name
if [ $# -eq 0 ]; then
[ $TODOTXT_VERBOSE -gt 0 ] && echo "Files in the todo.txt directory:"
cd "$TODO_DIR" && ls -1 *.txt
else
FILE="$1"
shift ## Was filename; next $1 is first search term
FILE="$1"
shift ## Was filename; next $1 is first search term
_list "$FILE" "$@"
fi
_list "$FILE" "$@"
;;
"listcon" | "lsc" )
@@ -1108,16 +1038,19 @@ case $action in
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"
[ -f "$src" ] || die "TODO: Source file $src does not exist."
[ -f "$dest" ] || die "TODO: Destination file $dest does not exist."
getTodo "$item" "$src"
[ -z "$todo" ] && die "$item: No such item in $src."
MOVEME=$(sed "$item!d" "$src")
[ -z "$MOVEME" ] && die "$item: No such item in $src."
if [ $TODOTXT_FORCE = 0 ]; then
echo "Move '$todo' from $src to $dest? (y/n)"
echo "Move '$MOVEME' from $src to $dest? (y/n)"
read ANSWER
else
ANSWER="y"
@@ -1130,10 +1063,10 @@ case $action in
# leave blank line behind (preserves line numbers)
sed -i.bak -e $item"s/^.*//" "$src"
fi
echo "$todo" >> "$dest"
echo "$MOVEME" >> "$dest"
if [ $TODOTXT_VERBOSE -gt 0 ]; then
echo "$item $todo"
echo "$item $MOVEME"
echo "TODO: $item moved from '$src' to '$dest'."
fi
else
@@ -1154,20 +1087,16 @@ case $action in
note: PRIORITY must be anywhere from A to Z."
[ "$#" -ne 3 ] && die "$errmsg"
[[ "$item" = +([0-9]) ]] || die "$errmsg"
[[ "$newpri" = @([A-Z]) ]] || die "$errmsg"
getTodo "$item"
oldpri=
if [[ "$todo" = \(?\)\ * ]]; then
oldpri=${todo:1:1}
fi
oldpri=$(sed -ne $item's/^(\(.\)) .*/\1/p' "$TODO_FILE")
if [ "$oldpri" != "$newpri" ]; then
sed -i.bak -e $item"s/^(.) //" -e $item"s/^/($newpri) /" "$TODO_FILE"
fi
if [ $TODOTXT_VERBOSE -gt 0 ]; then
getNewtodo "$item"
echo "$item $newtodo"
NEWTODO=$(sed "$item!d" "$TODO_FILE")
echo "$item $NEWTODO"
if [ "$oldpri" != "$newpri" ]; then
if [ "$oldpri" ]; then
echo "TODO: $item re-prioritized from ($oldpri) to ($newpri)."

View File

@@ -1,79 +0,0 @@
#!/bin/bash source-this-script
[ "$BASH_VERSION" ] || return
_todo()
{
local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
local -r OPTS="-@ -@@ -+ -++ -d -f -h -p -P -PP -a -n -t -v -vv -V -x"
local -r COMMANDS="\
add a addto addm append app archive command del \
rm depri dp do help list ls listall lsa listcon \
lsc listfile lf listpri lsp listproj lsprj move \
mv prepend prep pri p replace report shorthelp"
# Add custom commands from add-ons, if installed.
# TODO: Filter for executable flag of files found in $TODO_ACTIONS_DIR.
local allCommands="$COMMANDS $('ls' "${TODO_ACTIONS_DIR:-$HOME/.todo.actions.d}/" 2>/dev/null)"
local completions
if [ $COMP_CWORD -eq 1 ]; then
completions="$allCommands $OPTS"
elif [[ $COMP_CWORD -gt 2 && ( \
"${COMP_WORDS[COMP_CWORD-2]}" =~ ^(move|mv)$ || \
"${COMP_WORDS[COMP_CWORD-3]}" =~ ^(move|mv)$ ) ]]; then
# "move ITEM# DEST [SRC]" has file arguments on positions 2 and 3.
completions=$(TODOTXT_VERBOSE=0 todo.sh command listfile)
else
case "$prev" in
command)
completions=$COMMANDS;;
addto|listfile|lf)
completions=$(TODOTXT_VERBOSE=0 todo.sh command listfile);;
-*) completions="$allCommands $OPTS";;
*) case "$cur" in
+*) completions=$(TODOTXT_VERBOSE=0 todo.sh command listproj);;
@*) completions=$(TODOTXT_VERBOSE=0 todo.sh command listcon);;
*) if [[ "$cur" =~ ^[0-9]+$ ]]; then
# Remove the (padded) task number; we prepend the
# user-provided $cur instead.
# Remove the timestamp prepended by the -t option,
# and the done date (for done tasks); there's no
# todo.txt option for that yet.
# But keep priority and "x"; they're short and may
# 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
# completion can be a safety check before a
# destructive todo.txt operation.
[ "$todo" ] && COMPREPLY[0]="$cur # $todo"
return 0
else
return 0
fi
;;
esac
;;
esac
fi
COMPREPLY=( $( compgen -W "$completions" -- $cur ))
return 0
}
complete -F _todo todo.sh
# If you define an alias (e.g. "t") to todo.sh, you need to explicitly enable
# completion for it, too:
#complete -F _todo t