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.
This commit is contained in:
David A. Harding
2009-03-12 11:52:28 -04:00
parent d508ed9dee
commit f55f5e8b5f

280
todo.sh
View File

@@ -225,7 +225,7 @@ do
unset HIDE_CONTEXTS_SUBSTITUTION unset HIDE_CONTEXTS_SUBSTITUTION
else else
## One or odd value -- hide context names ## One or odd value -- hide context names
HIDE_CONTEXTS_SUBSTITUTION='[[:space:]]@[^[:space:]]\{1,\}' export HIDE_CONTEXTS_SUBSTITUTION='[[:space:]]@[^[:space:]]\{1,\}'
fi fi
;; ;;
'+' ) '+' )
@@ -241,7 +241,7 @@ do
unset HIDE_PROJECTS_SUBSTITUTION unset HIDE_PROJECTS_SUBSTITUTION
else else
## One or odd value -- hide project names ## One or odd value -- hide project names
HIDE_PROJECTS_SUBSTITUTION='[[:space:]][+][^[:space:]]\{1,\}' export HIDE_PROJECTS_SUBSTITUTION='[[:space:]][+][^[:space:]]\{1,\}'
fi fi
;; ;;
a ) a )
@@ -275,7 +275,7 @@ do
unset HIDE_PRIORITY_SUBSTITUTION unset HIDE_PRIORITY_SUBSTITUTION
else else
## One or odd value -- hide priority labels ## One or odd value -- hide priority labels
HIDE_PRIORITY_SUBSTITUTION="([A-Z])[[:space:]]" export HIDE_PRIORITY_SUBSTITUTION="([A-Z])[[:space:]]"
fi fi
;; ;;
t ) t )
@@ -323,7 +323,7 @@ export TODO_SH
[ -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"
@@ -339,61 +339,6 @@ fi
# === HEAVY LIFTING === # === HEAVY LIFTING ===
shopt -s extglob shopt -s extglob
_list-zero_padding() {
local LINES=$( wc -l $FILE_TO_NUMBER | sed 's/ .*//' )
local i=0
for i in $( seq 1 6 )
do
if [ $(( $LINES / 10 ** $i )) -gt 0 ]
then
:
else
break
fi
done
echo $i
}
_list-number_lines() {
local FILE_TO_NUMBER="$1"
local PADDING=$( _list-zero_padding "$FILE_TO_NUMBER" )
sed = "$FILE_TO_NUMBER" \
| sed "N; s/^/ /; s/ *\(.\{$PADDING,\}\)\n/\1 /" \
| sed '''
s/^ /00000/;
s/^ /0000/;
s/^ /000/;
s/^ /00/;
s/^ /0/;
'''
}
_list-sort_alphabetically() {
sort -f -k2
}
_list-add_priority_color() {
local FILE_TO_NUMBER="$1"
local PADDING=$( _list-zero_padding "$FILE_TO_NUMBER" )
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;
}'
}
_list-hide_priority_projects_contexts() {
sed 's/'${HIDE_PRIORITY_SUBSTITUTION:-^}'//g' \
| sed 's/'${HIDE_PROJECTS_SUBSTITUTION:-^}'//g' \
| sed 's/'${HIDE_CONTEXTS_SUBSTITUTION:-^}'//g'
}
# == HANDLE ACTION == # == HANDLE ACTION ==
action=$( printf "%s\n" "$1" | tr 'A-Z' 'a-z' ) action=$( printf "%s\n" "$1" | tr 'A-Z' 'a-z' )
@@ -560,108 +505,124 @@ case $action in
"list" | "ls" ) "list" | "ls" )
item=$2
if [ -z "$item" ]; then
echo -e "$( \
_list-number_lines "$TODO_FILE" \
| _list-sort_alphabetically \
| _list-add_priority_color "$TODO_FILE" \
| _list-hide_priority_projects_contexts \
)"
echo "--"
NUMTASKS=$(wc -l "$TODO_FILE" | sed 's/^[[:space:]]*\([0-9]*\).*/\1/')
echo "TODO: $NUMTASKS tasks in $TODO_FILE."
else
command=$(
_list-number_lines "$TODO_FILE" \
| _list-sort_alphabetically \
| _list-add_priority_color "$TODO_FILE" \
| grep -i $item
)
shift shift
shift exec "$TODO_SH" listfile "$TODO_FILE" "$@"
for i in $* ;;
do
command=`echo "$command" | grep -i $i `
done
command=$( \
echo "$command" \
| _list-sort_alphabetically \
| _list-hide_priority_projects_contexts \
)
echo -e "$command"
fi
cleanup ;;
"listall" | "lsa" ) "listall" | "lsa" )
item=$2
cat "$TODO_FILE" "$DONE_FILE" > "$TMP_FILE" cat "$TODO_FILE" "$DONE_FILE" > "$TMP_FILE"
if [ -z "$item" ]; then
echo -e "$(
_list-number_lines "$TMP_FILE" \
| _list-sort_alphabetically \
| _list-add_priority_color "$TMP_FILE" \
)"
else
command=$(
_list-number_lines "$TMP_FILE" \
| _list-sort_alphabetically \
| _list-add_priority_color "$TMP_FILE" \
| grep -i $item
)
shift shift
shift exec $TODO_SH listfile "$TMP_FILE" "$@"
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" ## If the file starts with a "/" use absolute path. Otherwise, make
## it relative to $TODO_DIR
if [ -z "$3" ]; then if [ "${2:0:1}" == / ]
item="" then
## Absolute path
src="$2"
else else
item=$3 ## Relative path
src="$TODO_DIR/$2"
fi fi
if [ -f "$src" ]; then
## Ensure the file exits before proceeding
if [ ! -f $src ]
then
echo "TODO: File $src does not exist."
fi
## Figure out how much padding we need to use
## We need one level of padding for each power of 10 $LINES uses
LINES=$( wc -l "$src" | sed 's/ .*//' )
i=0
## 6 places will pad tasks numbered less than 99,999, thus correctly
## displaying up to 999,999 tasks. Anyone who's done a million tasks
## should send me an email with your secret.
for i in $( seq 1 6 )
do
if [ ! $(( $LINES / 10 ** $i )) -gt 0 ]
then
break
fi
done
PADDING=$i
unset i LINES
item="${3:-}"
if [ -z "$item" ]; then if [ -z "$item" ]; then
## No search pattern specified, operate on whole file
echo -e "$( echo -e "$(
_list-number_lines "$src" \ sed = "$src" \
| _list-sort_alphabetically \ | sed "N; s/^/ /; s/ *\(.\{$PADDING,\}\)\n/\1 /" \
| _list-add_priority_color "$src" | 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;
}
s/'${HIDE_PRIORITY_SUBSTITUTION:-^}'//g
s/'${HIDE_PROJECTS_SUBSTITUTION:-^}'//g
s/'${HIDE_CONTEXTS_SUBSTITUTION:-^}'//g
''' \
)" )"
if [ $TODOTXT_VERBOSE = 1 ]; then if [ $TODOTXT_VERBOSE = 1 ]; then
echo "--" echo "--"
NUMTASKS=$( sed '/./!d' "$src" | wc -l | sed 's/^[[:space:]]*\([0-9]*\).*/\1/') NUMTASKS=$( sed '/./!d' "$src" | wc -l | sed 's/^[[:space:]]*\([0-9]*\).*/\1/')
echo "TODO: $NUMTASKS lines in $src." echo "TODO: $NUMTASKS lines shown from $src"
fi fi
else else
## Search pattern or patterns specified; parse the file and then
## grep for each pattern afterwords.
command=$( command=$(
_list-number_lines "$src" \ sed = "$src" \
| _list-sort_alphabetically \ | sed "N; s/^/ /; s/ *\(.\{$PADDING,\}\)\n/\1 /" \
| _list-add_priority_color "$src" \ | sed '''
| grep -i $item 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;
}
''' \
| grep -i "$item"
) )
shift shift ## was "listfile"
shift shift ## was first search pattern
for i in $* for i in "$@"
do do
command=`echo "$command" | grep -i $i ` command=`echo "$command" | grep -i "$i" `
done done
command=`echo "$command" | sort -f -k2` command=$( echo "$command" \
| sort -f -k2 \
| sed '''
s/'${HIDE_PRIORITY_SUBSTITUTION:-^}'//g
s/'${HIDE_PROJECTS_SUBSTITUTION:-^}'//g
s/'${HIDE_CONTEXTS_SUBSTITUTION:-^}'//g
''' \
)
echo -e "$command" echo -e "$command"
fi fi
else cleanup
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
@@ -673,38 +634,21 @@ case $action in
"listpri" | "lsp" ) "listpri" | "lsp" )
pri=$( printf "%s\n" "$2" | tr 'a-z' 'A-Z' ) if [ "${2:-}" ]
errmsg="usage: $0 listpri PRIORITY then
note: PRIORITY must a single letter from A to Z." pri=$( printf "%s\n" "$2" | tr 'a-z' 'A-Z' | grep '^[A-Z]$' ) || {
die "usage: $0 listpri PRIORITY
if [ -z "$pri" ]; then note: PRIORITY must a single letter from A to Z."
echo -e "$( }
_list-number_lines "$TODO_FILE" \
| _list-sort_alphabetically \
| _list-add_priority_color "$TODO_FILE" \
| grep \([A-Z]\)
)"
if [ $TODOTXT_VERBOSE = 1 ]; then
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" pri="[A-Z]"
fi
pri="($pri)"
echo -e "$( shift ## was "listpri"
_list-number_lines "$TODO_FILE" \ shift ## was priority
| _list-sort_alphabetically \ exec $TODO_SH listfile "$TODO_FILE" "$pri" "$@"
| _list-add_priority_color "$TODO_FILE" \ ;;
| grep \($pri\)
)"
if [ $TODOTXT_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
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 TODOTXT_PRESERVE_LINE_NUMBERS is 1