Drafts/nvALT/OmniFocus workflow for plain text notes

From your noodle to other noodles. Talk about ways to get the most from Hazel. Even exchange recipes for the cool rules you've thought up. DO NOT POST YOUR QUESTIONS HERE.

Moderators: Mr_Noodle, Moderators

[tl;dr]I have a Hazel rule that matches patterns in the filenames of notes I've created and runs an embedded shell script to prepend the text to the appropriate "master" text file. Another rule uses grep and AppleScript to find tasks (which always start with ## or ++) in those notes and send them to Omnifocus as either inbox tasks or "waiting for" tasks. A third set of rules renames the file using its first ten words. I'm using ten rules to accomplish this and think there must be a more elegant solution.[/tl;dr]

I keep a "master" text file for each of my clients, in which I try to keep all my meeting and telephone conversation notes, thoughts, tasks, reminders, etc. relating to that client. I also keep some other files that get updated regularly, like lists of books/apps/movies I want to check out, etc. Typically, I put these thoughts into either Drafts or nvALT. I didn't want to have to pull up the master file each time I had something to jot down, and that's not really possible to do in Drafts anyway. So, here's what I did:


First, I have nvALT save all notes to a Dropbox folder as separate text files. In that same folder, I have my "master" text files (all of which have filenames beginning with "@").

Second, I use a consistent naming convention for notes that correspond to a particular client, list, etc. This is basically a tagging system using the filename (which is generated from the first line of the note). For example, all my notes relating to client "Bob" will have a filename that contains "XBOB" (hat tip to Merlin Mann).

Because nvALT will open an existing file if it has the same first line as whatever you've typed in the search box, I needed to come up with a unique first line for each note. I didn't want to waste time coming up with something new each time, so I created a TextExpander snippet for each "tag." Whenever I type "XBOB" it prepends the date and time, so I get something like this: 20140326131043_XBOB. The snippet includes a carriage return, so once I type "XBOB" I'm ready to type my note, knowing that the first line of the note is unique filename and contains the appropriate tag.

nvALT automatically saves these notes to Dropbox. In Drafts, I created an Action that saves notes to the same folder, using the first line as the filename. This is where Hazel comes in. The Dropbox folder contains the "master" file, @Bob_Notes.txt. I want the note I just wrote to be added to the top of the master file, along with a date stamp. That way I can see the most recent stuff first. So I have a Hazel rule that applies to my Notes folder that acts on any file with XBOB in the name:
If all of the following conditions are met:
    Color Label is (X)
    Date Created is not in the last 5 hours
    Name contains XBOB
Do the following to the matched file or folder:
    Run shell script (embedded script)
    Set color label (PURPLE)

Since the rule makes the file purple once it has been acted on, the first condition makes sure the rule doesn't run twice on the same file. The second condition is to guard against the rule running on a note I'm in the middle of writing in nvALT.

Here is the embedded shell script:
Code: Select all
printf "~~ $(date +'%Y-%m-%d %H:%M') ~~\n\n" >> BOBTEMP.txt
cat "$1" >> BOBTEMP.txt
printf "\n\n" >> BOBTEMP.txt
cat @Bob_Notes.txt >> BOBTEMP.txt
rm @Bob_Notes.txt
mv BOBTEMP.txt @Bob_Notes.txt

What this does is create a temporary file (BOBTEMP.txt), and adds a date-stamped header at the top that looks like this (plus a couple of carriage returns):
~~ 2014-03-25 19:02 ~~

Then it appends the full text of the note file on which the rule is acting, so that gets added under the date-stamped header. Then it adds another blank line:
~~ 2014-03-25 19:02 ~~

Remember to ask Bob about his root canal

Then the entire contents of the master file (@Bob_Notes.txt) is appended into the new temporary file, beneath the most recent note. The master file is deleted, and the temporary file is renamed to become the master file.


I have two rules that scan new note files for tasks. Whenever I'm writing down a task I need to do later in a note, I start it with "##". If it is a task someone else needs to do, I start it with "++". Both rules work the same way:
If all of the following conditions are met
    Date Last Modified is not in the last 5 minutes
    Date Last Modified is after Date Last Matched
    Contents contain "##"
Do the following to the matched file or folder:
    Run AppleScript (embedded script)
    Run Shell Script (embedded script)

As before, the first two conditions are to avoid having the rule act while I'm in the middle of jotting down the task. First I run an AppleScript to send the task to OmniFocus:
Code: Select all
set p to POSIX path of theFile
set l to paragraphs of (do shell script "grep '##' " & p)

tell application "OmniFocus" to tell document 1
   repeat with v in l
      make new inbox task with properties {name:v}
   end repeat
end tell

This script uses grep to find all lines in the file that begin with "##" and tells OmniFocus to create a new inbox task out of each one. Then I run a shell script using sed to change the ##'s to XX's to avoid duplicate tasks:
Code: Select all
sed -i "" s/##/XX/g $1

The ++ tasks (tasks I'm waiting for others to do) are dealt with the same way, except that I add the "Waiting" context in the AppleScript:
Code: Select all
set p to POSIX path of theFile
set l to paragraphs of (do shell script "grep '++' " & p)

tell application "OmniFocus" to tell document 1
   set theContext to first flattened context where its name = "Waiting"
   repeat with v in l
      make new inbox task with properties {name:v, context:theContext}
   end repeat
end tell


I keep the original notes, as a backup and because they can be easier to deal with when I'm searching for something specific in nvALT. So that the filenames ("20140326131043_XBOB") provide a bit more information, I rename them using the first line of actual text. However, after much trial and error this ended up requiring ten different rules.

Some of my notes can be very short. I couldn't figure out a way to tell Hazel to rename the file using the first line, so I eventually tried using custom tokens that took the first ten occurrences of (abc) matched in the contents of the file, and renaming using those ten tokens in a row, separated by spaces. The problem was, the rule got stuck on files of fewer than ten words. The fewer words I use in my rule, the less information the filename contains. Then I tried using an "if any" subcondition that checked for a tenth-word match, then a ninth-word match, then an eighth and so on. The problem with that was that Hazel stopped checking for matches (and, apparently, therefore stopped assigning values to the custom tokens) once it got a result, so I ended up with one-word filenames.

Finally, what I ended up with was ten variations of this:
If all of the following conditions are met
    Color Label is (purple)
    Name matches (ab12)_(*tag)
    If all of the following conditions are met for the current file or folder
      Contents contain match (*tenth word)
      Contents contain match (*ninth word)
      Contents contain match (*eighth word)
      Contents contain match (*seventh word)
      Contents contain match (*sixth word)
      Contents contain match (*fifth word)
      Contents contain match (*fourth word)
      Contents contain match (*third word)
      Contents contain match (*second word)
      Contents contain match (*first word)
Do the following to the matched file or folder:
    Rename with pattern (*tag) - (*first word) (*second word) (*third word) (etc...)(extension)
    Set color label (RED)

The (*tag) token finds "X(ab12)" in the filename, and the rest of the custom tokens use the "occurence" option to match (123) in the contents of the file. Those tokens are used to rename the file. Then the file is marked red, which prevents the rules that come after from running (because they all require the file to be purple to run the rule). The next rule starts at "ninth", then "eighth", and so on.

I can't help but think there's an easier way to do this (and preferably one that gets the whole first line, and just the first line, no matter how long or short it is).
Posts: 3
Joined: Mon Mar 10, 2014 2:22 pm

Return to Tips & Tricks - DO NOT POST QUESTIONS