First of all, there have been some major updates to Doing over the last few weeks (changelog), so be sure to update to the latest version (gem update doing). If you don’t know what Doing is and started reading this post anyway, go check it out first.

I’ve been playing with incorporating Doing into my iTerm status bar. It’s already in my Touch Bar, but having it right below my prompt in my terminal seemed super handy. The method I’m using might seem a bit convoluted, but it’s working great.

This whole thing is based around iTerm’s user variables and interpolated strings. Once set, the variable can be used in status bars, window titles, session badges, etc. You just have to keep it updated, so some hooks are required. Here’s how I got it working.

Getting the Current Entry

First we need to get the text to display. I set up a view for Doing to display just a single entry, title only, no color. It should be the most recent entry not marked @done. I’m using the same view I set up for my Touch Bar with BetterTouchTool:

In ~/.doingrc:

views:
  btt:
    section: Currently
    count: 1
    order: desc
    template: "%title"
    tags_bool: NONE
    tags: done

Now when I run doing view btt I get just the most recent unfinished entry.

Keeping It Up to Date

Rather than repeatedly running this command I’m storing the result in a cache file where I can just cat to retrieve it. It only needs to update when there’s a change to my doing file.

In recent version of doing there’s a key you can set in your config to run a script after doing performs any operations that change your doing file. I already had this set up to refresh my Touch Bar, so I just added to the existing script. To run a custom script (in this case after_doing.sh), just make sure it’s executable (chmod a+x after_doing.sh) and add a line to ~/.doingrc:

run_after: /path/to/after_doing.sh

In after_doing.sh, I just cache the doing view results and use iTerm escape codes to set the user variable. The set_user_var function is clipped from the various iTerm shell integration functions, combined for easy access and accessibility without a login shell. Here’s the part of the script minus the other non-iTerm stuff I run:

#!/bin/bash

set_user_var ()
{
    printf "\033]"
    printf "1337;SetUserVar=%s=%s" "$1" $(printf "%s" "$2" | base64 | tr -d '\n');
    printf "\007"
}

doing view btt | tr -d "\n" > ~/.doing_cache
set_user_var doingNow "$(command cat ~/.doing_cache)"

So when doing has made a change and runs the script, it first outputs the doing view result to a hidden cache file. If there’s no current unfinished entry, this will be blank. Then the script sets the initial value of the variable. The setting of the variable is actually optional, as we’re going to be doing that again every time the prompt is displayed. If you wanted to pare it down, only the doing view line is really needed.

Updating the iTerm User Variable

Now we need a way to refresh the variable. I chose to do it with a prompt command, running every time the prompt displays. Since all it’s going to do is cat a tiny text file, there’s no performance hit. I suppose you could set up some kind of polling, but this seems like the best solution.

These examples use functions created by the iTerm shell integration. If you haven’t already, go to iTerm->Install Shell Integration to add the tools to your current shell.

In a fish_prompt function:

iterm2_set_user_var doingNow (command cat ~/.doing_cache)

Or in a bash prompt_command:

iterm2_set_user_var doingNow "$(command cat ~/.doing_cache)"

I’m not good enough with zsh to offer a proper example, but the same thing should be doable in precmd.

Setting Up the iTerm Status Bar

Lastly, we set up the iTerm status bar to make use of the variable we’ve populated.

In iTerm, go to Preferences->Profiles, select the profile to edit (probably the default), switch to the Session tab, and click Configure Status Bar at the bottom. Drag an interpolated string component into the status bar. Click Configure Component and set it to display \(user.doingNow). Set a background color and minimum width of 0. Now you have your current doing entry in your status bar, updating every time the prompt displays.

iTerm 2 Custom Action component configuration

You can alternatively use a Custom Action component, which allows you to perform an action when you click it. I’m using this to complete the displayed entry. To use a Custom Action, add the component to the status bar and click Configure Component, then click Configure Action. Set the title to \(user.doingNow), and the Action to Run Coprocess. For the command you’ll need the full path to the doing executable (run which doing). Set the command to finish the current task: /path/to/doing finish -u --auto &>/dev/null. That will mark the last unfinished entry as done (even if it’s not the most recent) and set the completion date to the start date of the next entry (or the current time if it’s the most recent entry). The &>/dev/null is needed to mute all output from the command so iTerm doesn’t assume there was an error and present a warning. Now I get a display of my current unfinished entry, and clicking it completes it for me. (If you use @meanwhile tasks and want older entries to have current finish dates, just leave off --auto).

Doing in the status bar