Auto-Print Daily Agenda

Posted on February 7th, 2015

I moved somethings around in my office recently so I could get back in the habit of using my standing desk1 more often. Here’s what it looks like at the moment:

[Picture of my Standing Desk]

My setup is still in flux,2 but one of the niceties is that it puts my computer right near my printer. This actually ties in with something else that I have been doing as an aid for productivity. Before I go to bed, I take a look at my calendar for the next day as well as my flagged OmniFocus tasks. (I used flags in OmniFocus to indicate that although something may not have a specific due date, it needs to be done relatively soon.) Then I decide on three things that I want to work on the next day.

I want a printout of those 3 things, for a few reasons:

  1. It’s a handy and quick reference that I can look at any time.

  2. It’s very satisfying to cross things off a printed list with a pen.

  3. When I think of more things that I need to do during the day, I write them on the list.

    • If they don’t get done, I add them to OmniFocus.

    • If they do get done, I have a record of what I did. (This is especially helpful for writing down things I did which might have prevented me from doing all 3 of the things I had planned to do.)

I don’t want to print that list out at home and have to remember to bring it with me to the office, like some kind of wild animal. That would just be another thing I have to remember to do. No, I want it to just be there when I get to the office tomorrow.

So. How can I do that?

There are many ways, this is mine.

The easiest way to do this is using some method that syncs automatically. I decided to use Byword because I already had it installed on my iPad, iPhone, and my work Mac.

Then I had to decide if I was going to use Dropbox or iCloud to sync. My work Mac does not have Dropbox installed, so that left iCloud. Byword has always done well with iCloud syncing, so I felt OK using that, despite my general unease about iCloud Drive.

My first thought was to use Keyboard Maestro to select File » Print and then click the "Print" button to print the file every morning at 7:00 a.m. but then I realized that wouldn’t work because Keyboard Maestro cannot manipulate menus when Mac is locked, which it would be at that time.

So I needed to print some other way.

I thought about having Hazel or launchd monitor the file and print it whenever there were changes, but that is a terrible idea, because every time I clicked "Save" or if Byword saved it automatically, another piece of paper would be wasted. I had visions of coming in to find a stack of paper waiting for me.

So I decided that I would print the document at 7:00 a.m.

Since the file is just plain text, I could have printed it using the old Unix standby lpr:

lpr /path/to/file.txt

That’s where I should have stopped…

…but I was curious to figure out what it would take to get it printed as interpreted Markdown (where underscores would mean italics, etc). I had pandoc installed, and thought "Oh, I will just have it convert the Markdown to PDF."

It sounded simply enough, except that it required TeX to be installed. Fortunately, I had that downloaded already (it’s a 2 GB download!) so all I had to do was install the pkg and add /usr/texbin/ to my $PATH. Once that was done, I could create a PDF using:

pandoc -r markdown_mmd -t latex -o "$PDF" "$FILE"

where $FILE is the path to the Markdown file in iCloud3 and $PDF is the path to the PDF that I wanted to create. I decided to save the PDF to my Desktop, in case I wanted to refer to it later in the day, so, for me, those two variables look like this:

FILE="$HOME/Library/Mobile Documents/N39PJFAFEV~com~metaclassy~byword/Documents/Three Things.txt"

PDF="$HOME/Desktop/ThreeThings.pdf"

Once I have the PDF, I could print it using good ol’ lpr again:

lpr "$PDF"

Ok, now that I got that out of my system…

The script also needed some basic “sanity checking.” For example, if the file hasn’t been changed since the last time it was printed, there’s no need to print it again.

I use md5 to save the checksum of the file whenever it is printed, and whenever the script runs again, it checks to see if the new md5 is different. If it hasn’t changed, the script won’t even bother (making the PDF and) printing it.

Last but not least, I needed a way to run the script every day.

Well, not every day. I just want it to run Monday-Friday.

Fortunately, launchd will let you specify which days you want it to run, which you can do in LaunchControl by choosing the “StartCalendarInterval” Configuration Key:

[Screenshot of Start Calendar Interval in LaunchControl]

Pro/Power User Tip: Add StartCalendarInterval Times using cron Syntax

One of the things I love about LaunchControl is that it makes everything about launchd easier. In fact, you can even use cron to set the days and times that you want something to run. This can help you avoid a lot of tedium if you want to use a recurring time like “every 15 minutes” or some other configuration. One of my main gripes with using launchd instead of cron was that cron had this syntax built-in. Now I can use it again with LaunchControl.

Of course, despite having used cron for 20+ years, I never remember the exact sequence, but fortunately LaunchControl gives me a handy tooltip to remind me:

[screenshot of Start Calendar Interval in LaunchControl]

Oh right, so I need 0 for the minute, 7 for the hour * for the “day of month” and “month of year”, and 1-5 to refer to Monday-Friday. You can see that in the blue highlighted area of that screenshot.

That tooltip was hiding the “Generate” button, which tells LaunchControl that you are done entering cron ranges and ready for it to interpret what you told it.

[Screenshot of LaunchControl showing cron format for Start Calendar Interval]

After I clicked that, all the intervals were entered, so I could make sure that they matched up what I had in mind. Can’t say enough good stuff about LaunchControl.4

Installation Instructions

1) Download my shell script, install it in /usr/local/bin, and make it executable, like this:

cd /usr/local/bin

curl -LOf --progress-bar https://gist.githubusercontent.com/tjluoma/49b28ef83709346b063f/raw/a72f8a6d3c99c10f04e86d72decd67d2f3091af5/print-three-things.sh

chmod 755 print-three-things.sh

2) Edit the $FILE line from print-three-things.sh

FILE="$HOME/Library/Mobile Documents/N39PJFAFEV~com~metaclassy~byword/Documents/Three Things.txt"

3) (Optional) Edit the $PDF line from print-three-things.sh if you want the PDF saved somewhere else, or with a different name:

PDF="$HOME/Desktop/$NAME.ThreeThings.pdf"

4) Download my launchd plist from GitHub and install it to ~/Library/Launch Agents/ like this:

mkdir -p ~/Library/Launch\ Agents/

cd ~/Library/Launch\ Agents/

curl -LOf --progress-bar https://gist.githubusercontent.com/tjluoma/b8551ceb68dec6bed6d5/raw/57e9a67e115c4f8d40564d5d39817f8354fe496d/com.tjluoma.print-three-things.plist

launchctl load com.tjluoma.print-three-things.plist

5) Make sure that you have pandoc installed. Type which pandoc in Terminal and you should see something like this:

> which pandoc
/usr/local/bin/pandoc

If you get pandoc not found then you will have to install it, either with the pandoc package from its release page. or, if you use Homebrew, you can install it via:

brew install pandoc

Uninstallation

Unload the plist from launchd:

launchctl unload ~/Library/LaunchAgents/com.tjluoma.print-three-things.plist

Move the plist and the shell script to Trash:

mv -vn /usr/local/bin/print-three-things.sh \
~/Library/LaunchAgents/com.tjluoma.print-three-things.plist \
~/.Trash/

That’s it.

Using It

I have a reminder in Due which goes off at 9:00 p.m. every Sunday-Thursday to remind me to update my “Three Things” for the next day.

I open up Byword, open the file, select all, and type Tngs which is my TextExpander shortcut for “Things”. It is defined as:

    Title: %@+1D%A, %B %d, %Y

    1.

%@+1D%A, %B %d, %Y expands to tomorrow’s date (i.e. “Monday, February 09, 2015”), starts a Markdown list, and leaves the cursor ready to enter the first item. Since Byword is Markdown-savvy, when I press Enter it will make the next item #2, and so on. When I’m done editing the file, it sync’s via iCloud back to my Mac mini. The next morning at 7:00 a.m., it prints so it is waiting for me when I get to the office around 7:30 a.m.

I set this up last night, and so far it has worked great. Ok, it’s only been one day, and it’s not going to replace OmniFocus but it’s not intended to, it’s intended to be a guide for today, as well as a place to make notes during the day. I look forward to starting to use it for real next week.


  1. I’ve had this desk for about 5 years now. I wrote about it on TUAW (Case Study: Standing at your Mac to save your back) back in 2010. At the time I noted that it had cost me $96, but was regularly selling for $277 plus shipping. Today, it sells for $278, so obviously I got lucky. It’s not a particularly good desk, I certainly wouldn’t spend almost $300 on it, but it’s functional. I have a traditional desk that I use when I need to sit down. Looking back at that article, the biggest shock was remembering when I used an iMac plus another screen of a different size. Yuck. I much prefer my 2560x1080 Dell UltraSharp U2913WM 29" monitor vs two separate monitors. 

  2. You’ll notice my Fujitsu ScanSnap iX500 — a perennial MacPowerUsers favorite — sitting on the floor. 

  3. Isn’t that a pretty path? Much nicer than, say, ~/Documents/iCloud/Byword/Documents/. Apple really wants you to pretend that these files aren’t part of the filesystem. 

  4. If you do anything with launchd or especially if you want to learn how to use launchd, LaunchControl is great. It has explanations of all the various features of launchd including a search feature I use all the time when I can’t remember the name of some launchd criteria. For example, in the second screenshot above, see on the right-hand side where I typed ‘cron’? That was because I couldn’t remember “StartCalendarInterval” but I knew that LaunchControl’s description of it referred to ‘cron’. So I searched for the word I remembered, and it showed me the launchd configuration key that I wanted. 

Show or Hide hidden files without restarting Finder

Posted on February 3rd, 2015

Mac OS X will hide files which begin with a “.” or other files which have been hidden with the SetFile command in Terminal:

SetFile -a V /path/to/file.txt

The “old way” of toggling this was to do

defaults write com.apple.finder AppleShowAllFiles -boolean false

or

defaults write com.apple.finder AppleShowAllFiles -boolean true

followed by

killall Finder

but that will also cancel any move/copy processes that Finder is doing, and is generally gross. I mean, if you have to restart the Finder, that’s one thing, but who wouldn’t prefer to avoid that if they could?

This AppleScript, found at AskDifferent showed me how to toggle between showing and hiding hidden files without having to restart the Finder.

As you might have guessed, that will “toggle” the current setting, and then refreshed all of the Finder windows. In my testing over the past few days it seems to work great on 10.10.2.

The only downside to this is that it does not change the Desktop. To do that you must restart Finder. To workaround this, just navigate to ~/Desktop/ in a Finder window. However, when you log in to your user account on your Mac, Finder will either show or hide hidden files on the desktop depending on whatever the setting was when you logged out or restarted. So be sure to leave it the way that you want it to be when you come back.

How to Run That Applescript

Now that you have the AppleScript, how will you run it? Two options are FastScripts or Keyboard Maestro. I prefer the latter just because it does so many other things as well.

Here’s what it looks like in Keyboard Maestro:

  1. “ » Finder” is a group which is defined to only be active when I am in the Finder.
  2. The name of the macro
  3. Shows the keyboard shortcut ⌥ + H which I use to toggle show/hide
  4. Is where you paste the AppleScript

If you want to use my Keyboard Maestro macro, you can download the Keyboard Maestro macro here, or, if you just want the AppleScript, grab the gist from GitHub.

To use the Keyboard Maestro macro, double click to unzip it, and then double click the .kmmacros file to import it into Keyboard Maestro.app. It will automatically create the “» Finder” group for you. (You can, of course, rename that group to be called whatever you want.)

Bonus Tip

If you have hidden a file using

SetFile -a V /path/to/file.txt

and do not want it to be hidden anymore, you can undo it by

SetFile -a v /path/to/file.txt

Note the V versus v? Little v shows, big V hides.

Keep Desktop Clean By Name

Posted on February 2nd, 2015

I try not to keep a lot on my desktop, but sometimes it’s hard to avoid. What is there I like to have tidy, which means that I am frequently doing Finder » Clean Up By » Name

The first problem is that this only works if there are no other Finder windows open. Plus, it’s annoying to have to keep doing this every time the Desktop changes.

Enter AppleScript.

Thanks to this post on AskDifferent I found that the AppleScript command I wanted was:

    tell application "Finder" to clean up window of desktop by name

or in shell script format:

    osascript -e 'tell application "Finder" to clean up window of desktop by name'

that worked just fine. Now I just needed a way to do it automatically whenever the Desktop changed. I could use Hazel for this, but for simple folder monitoring and triggering, I prefer launchd:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>Label</key>
        <string>sync.com.tjluoma.cleandesktop</string>
        <key>ProgramArguments</key>
        <array>
            <string>/usr/bin/osascript</string>
            <string>-e</string>
            <string>tell application "Finder" to clean up window of desktop by name</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
        <key>WatchPaths</key>
        <array>
            <string>/Users/luomat/Desktop</string>
        </array>
    </dict>
    </plist>

Translation: “Any time the /Users/luomat/Desktop/ folder changes, run osascript -e 'tell application "Finder" to clean up window of desktop by name'

Obviously you’ll need to change <string>/Users/luomat/Desktop</string> to the proper path for your $HOME.

To Install

  1. Download gist from GitHub
  2. Change /Users/luomat/ to whatever your $HOME directory is
  3. Move file to ~/Library/LaunchAgents/sync.com.tjluoma.cleandesktop.plist (you can use whatever name you like, just be sure it ends with .plist)
  4. To activate it, run this in Terminal:

    launchctl load ~/Library/LaunchAgents/sync.com.tjluoma.cleandesktop.plist

To Uninstall:

In Terminal:

    launchctl unload ~/Library/LaunchAgents/sync.com.tjluoma.cleandesktop.plist

    mv ~/Library/LaunchAgents/sync.com.tjluoma.cleandesktop.plist ~/.Trash/

The first line disables it in launchd and the second moves the plist to the trash folder so it won’t be used in the future.

Teaser

Wondering why I called it sync.com.tjluoma.cleandesktop.plist instead of com.tjluoma.cleandesktop.plist? I’ll explain that in another post.