My Command Line Todo List

I was looking for a quick and easy way to track my todo’s at work. One thing I wanted was to see only one task at a time. Because I spend a fair amount of my day on the command line, I thought it would be relatively easy to implement this on the command line.

I keep a .zshrc file with a handful of functions and aliases. I figured I could probably add a few commands to that file to make this work. Here are the commands I have today.

todo [item] Add an item or edit the todo list
next        List the next todo item on my list
soon        List the next 10 items on my list
late        List items completed lately
mark [item] Mark the current item (or [item]) as done

The Plain Text Todo File

I decided to keep my todo list in the plain text file ~/todo.txt. This allows me to use it right now and lets me take an iterative approach to the rest of the tools described here. At first I had a simple alias that just opened my todo list in my favorite editor.

alias todo=$EDIT ~/todo.txt

That uses a variable for my editor. My main editor is currently VS Code so I have a variable assigned to that. This gives me the freedom to switch all my commands to a different editor if I decide to do so in the future.

export EDIT=code

Adding an Item

I wanted it to be super easy to add a line to my todo list, without opening my editor, so I wrote a little function to do so. If I don’t include an argument my todo list will still open in my default editor but if I do add an argument it will simply append that to my file.

So, to open my todo.txt file in my favorite editor I still run:

todo

But, to add a new item I can also run:

todo "Make something amazing happen."

Here’s the short function I’m using for the todo command today.

function todo() {
    if [[ $# -eq 0 ]]; then
        $EDIT ~/todo.txt
    else
        echo $* >> ~/todo.txt
    fi
}

Seeing the Next Item

Most of the time I only want to see my next highest priority item so that I can focus on just that. I keep my todo list in priority order so the most important item is at the top. To view that top item I just need a simple alias that shows me the first line.

alias next="head -1 ~/todo.txt"

Other Priorities Coming Soon

Once in a while, however, I’ll want to see a list of the most important upcoming items. I decided that seeing the next 10 items on the list would do the trick. I also wanted them to have a little more fancy output. Here’s my alias for that.

alias soon="head -10 ~/todo.txt | sed 's/^/- /'"

Marking Items as Done

I decided I wanted to keep a history of the items I’ve finished. This has become the most complicated part of this little tool. I wanted to be able to do two things. First, I wanted to be able to mark my most important item, the one I’m working on now, as done. For that I use the mark command.

Next, I wanted to be able to mark an item done that wasn’t on my todo list. Something that I did in the moment because it was easier than adding it to my list. For that I use the mark command with an argument. For example:

mark "Added John to the Core team on GitHub."

I wanted to date stamp these finished items so that I would know when I had completed them.

I also wanted to keep backups in case something went wrong when I was adding stuff to this file.

Here’s the full mark function that I’m using today.

function mark() {
    # Backup the file
    local timestamp=$(date +'%Y-%m-%d')
    cp ~/todo.txt /tmp/todo-${timestamp}.txt
    
    if [ "$#" -eq 1 ]; then
        # Use the provided argument
        local LINE="$1"
    else
        # Pull the first line from todo.txt
        LINE=$(head -1 ~/todo.txt)
    fi

    # Output the provided line or first line of todo.txt into the done file and date stamp it
    echo "$LINE [$(date +'%Y-%m-%d')]" >> ~/done.txt

    # Show the completed item now that we've logged it
    tail -1 ~/done.txt

    if [ "$#" -eq 0 ]; then
        # Output everything but the first line of todo.txt back into todo.txt only if no argument is provided
        sed 1d ~/todo.txt > /tmp/todo.txt
        mv /tmp/todo.txt ~/todo.txt
    fi
}

Listing Items Completed Lately

Once in a while I’ll need to quickly describe what I’ve been up to. This is useful for status meetings, 1-on-1’s, and other times you’re looking for things of interest to talk about. This command shows me the last 10 items I recorded doing.

alias late="tail -r -n 10 ~/done.txt"

Getting Help

Finally, I have a little help function that shows me all the tools I’ve setup in my .zshrc file. For my todo list I’ve got the following function.

help() {
    echo "Todo:"
    echo "  todo [item] Add an item or edit the todo list"
    echo "  next        List the next todo item on my list"
    echo "  soon        List the next 10 items on my list"
    echo "  mark [item] Mark the current item (or [item]) as done"
    echo "  late        List items completely lately"
}

Comments

Love it. A concise junction of alias and function usage. Search “shell functions” for my interests.

By Martin on August 18, 2024