I've tried (and failed) to use many different pieces of software designed to manage todo lists. The main reasons I've failed is because the software either has a high learning curve, bad documentation, or it is cumbersome to use.
I've finally struck gold with devtodo. Out of the box, it is almost perfect, but there are a few little issues:
- It expects .todo in the current directory
- It has no ability to track what you are working on.
I've managed to work around both of those with some extra functions in my .bash_profile.
Where is my .todo?
I wanted a git-like approach to my todo list. If there is not one in the current directory, check the parent, the grandparent, etc. Eventually, fall-back to 'Global' todo list in ${HOME}.
Note: This depends on the rfind function in my previous post.
First, create a function to set the TODO_FILE variable. We're going to set TASK_FILE here as well, this is referenced further down the page.
set_nearest_todo_file()
{
ntdf_file=$( rfind -name .todo -type f )
if <span class="createlink"> -z "${ntdf file}" </span>; then
ntdf_file="${HOME}/.todo"
fi
TODO_FILE="${ntdf_file}"
}
set_nearest_task_file()
{
TASK_FILE="${TODO_FILE}-current"
}
Now, we need to call these on cd, pushd, and popd, as well as when the shell is sourced.
cd()
{
if builtin cd "$@"; then
set_nearest_todo_file
set_nearest_task_file
fi
}
pushd()
{
if builtin pushd "$@"; then
set_nearest_todo_file
set_nearest_task_file
fi
}
popd()
{
if builtin popd "$@"; then
set_nearest_todo_file
set_nearest_task_file
fi
}
set_nearest_todo_file
set_nearest_task_file
Next, lets make an alias for td
to call devtodo with our desired
todo_file
td()
{
# Don't print DB notice for .todo in current dir
if <span class="createlink">.todo" </span>; then
# Output DB notice to stderr.
# so we don't mess with output parsers
echo "Using database ${TODO_FILE}" 1>&2
fi
# Specify found DB
devtodo --database ${TODO_FILE} $@
}
Now, when we call td
, we will be referencing the nearest TODO_FILE,
either in the current directory, one of it's parents, or falling back to
${HOME}.
What am I working on?
This was simple enough. devtodo has aliases for todo (devtodo), tda
(todo --add) and tdd (todo --done). We also added td
above. I'm going
to hijack tdd, and add a new 't' command to set a current task.
We already added the neccessary parts to get TASK_FILE above. Now we're just going to create a function to set a task in that file.
t()
{
if <span class="createlink"> "$*" == "" </span> ; then
if <span class="createlink"> -f "${TASK FILE}" </span>; then
cat ${TASK_FILE}
fi
else
td $@ | tee ${TASK_FILE}
fi
}
You'll notice that if we call t
with a parameter, such as t 6
, it
run td 6
, instruct td to show task 6, and copy that output to your
TASK_FILE.
If we simply call t
, it will cat out our TASK_FILE to the screen.
I've also hijacked tdd
, the devtodo 'done' alias, to clear my
TASK_FILE as well.
tdd()
{
/usr/bin/tdd $@
rm ${TASK_FILE}
}
My workflow
I find this very easy to manage. td
to review my list, t #
to select
my active task, and t
while I'm working to be reminded what I'm doing.
The task number is still in the output of t
. When I'm done, tdd #
marks that task as complete, removes TASK_FILE, and I'm free to start
another task.