This week Dr. Drang wrote about a useful feature in recent versions of
OS X’s Terminal.app,
which allows you to display a man page in its own special window.
This is especially useful when you want to look something up but you are in the
middle of typing a long command.
It’s not polite to respond to a good solution to a common problem
by claiming to have
a better solution, and even less so when the better solution requires you to
change your shell. But this is the internet, so here goes.
When I need to look at a man page while writing a command, I use zsh’s
push-line editing command.
This clears the prompt and waits for you to type something else.
After executing this new command, it restores your original prompt.
The nice thing about this is that it is useful beyond just looking at manuals.
Often while typing some command,
I realize I need a quick
cd or even
ls before I’m ready to
You can bind
push-line to a key (I use Ctrl-B) by putting
bindkey '^B' push-line
Even better, you can use
push-line-or-edit to get the same behavior
with one very useful addition. Normally, if you are typing a continuation line
of a multi-line command, you cannot make changes to prior lines.
push-line-or-edit redraws the lines as a single block of text,
which allows you to edit anything you have typed so far.
When I started using a script to add items to my TaskPaper file,
I was a little worried about the script making changes to my file while it
was open in TaskPaper. So I used TaskPaper’s preference to save
my files every five seconds, and nothing bad happened for a while.
Then I started seeing corrupted files. It seems like OS X autosave is doing
something weird. If I poke at it, I can get parts of the file go missing,
or sometimes a dialog box pops up to complain. But everything works fine as
long as I do an actual “⌘S” save.
To prevent corruption, I added
a few lines to my shell script, which use AppleScript to save my
TaskPaper file before making the changes.
I use pgrep to check if TaskPaper is running, and a
heredoc to send the text of the script to the
if pgrep TaskPaper > /dev/null; then
/usr/bin/osascript << EOM
tell application "TaskPaper"
repeat with Doc in documents whose name is "tasks.taskpaper"
(It is so much easier to embed AppleScript in a bash script than the other
The most widely read post on this site is my 2012 post on scheduling tasks
using launchd. But my knowledge of launchd is limited to my
experience. In particular, I was mistaken about how to set up a task when your
computer has multiple accounts.
(For many years, my wife and I shared an account, mostly because it’s still so
difficult to switch between
accounts and properly share files. But now, with iPhones and
iCloud, it’s even more painful to share an account, so we finally split things
In my post, I wrote:
If you have multiple users and need something to
run no matter who is logged in, you should look into putting it in
But this isn’t quite right. For system-wide jobs, there are two
folders that can
contain your Launch Agent plists:
The difference is that system-wide Launch Agents
run exactly like per-user
Launch Agents, except that they run once for each user. If you have two users
logged in, the system will run two instances of the Launch Agent job.
Each job will run with that user’s permissions. (This may actually
cause problems. For example, if you need to write to a file, you must use a
different file for each user or use a file that is world-writable.)
Launch Daemons, on the other hand, spawn a single instance, regardless of who is
or is not logged in. By default, these run with root permissions (be careful!),
although you can (and almost always should) customize this with the
Here’s my new favorite way to get tasks into TaskPaper.
It’s a combination of Drafts, Dropbox,
launchd, a Python script, and
a shell script.
That sounds convoluted, but once each piece of the pipeline
is in place, I just enter one or more tasks into Drafts on my phone,
and three seconds later, it is in my TaskPaper file on my Mac.
It’s like iCloud, but without the mystery.
Merge new tasks into TaskPaper
I wrote a Python script to insert new tasks in the proper place
in my TaskPaper file. Since TaskPaper files are just plain text, this is not too
My script reads in a text file and interprets each line as a new task. If the
task has a project tag, it removes the tag, and then it groups the tasks by
project. Anything without a project is assumed to be in the inbox. Next, it
reads my main TaskPaper file, and figures out where each project begins and
ends. Finally, it inserts each new task at the end of the appropriate project.
A shell script calls the Python script with the correct arguments, merging
inbox.txt file into my
tasks.taskpaper file, and deleting the
inbox.txt file. Update: To avoid corrupting
my TaskPaper file, I use some AppleScript within this shell script
to first save the file if it is open.
(Of course, the Python script could have done these last steps also, but it’s much
better to make the Python script generic, so I can use it for other purposes.)
Watch inbox for changes
The next step is to automate the merging. This is where OS X’s launchd
is useful. One solution would be to run the shell script on some kind of timed
interval. But launchd is smarter than that.
WatchPaths key, I can have the shell script run whenever my
file is modified.
Since OS X keeps an eye on all filesystem changes, this actually
has a very low overhead and means that my shell script will be run within seconds
of any modifications to
Here is my Launch Agent definition, stored in a plist file in
1: <?xml version="1.0" encoding="UTF-8"?>
2: <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3: <plist version="1.0">
Drafts and Dropbox
With the hard work out of the way, I just define a custom Dropbox action in Drafts
that appends text to
inbox.txt in my Dropbox folder.
With no fuss, Drafts sends the new task or tasks off to Dropbox, which dutifully
copies them to my Mac, which springs into action, merging them into my TaskPaper
With so many applications and services fighting to be the solution to all of our
problems, it is refreshing to see tools that are happy solving their portion
of a problem and letting you go elsewhere to solve the rest.