An AppleScript to Create an Apple Mail Message from a VoodooPad Page

More VoodooPad scripting fun. I needed to email the contents of a VoodooPad page the other day, so I whipped this up. It generates an email in Mail.app using the contents of the current VoodooPad page.

(* An AppleScript to Create an Apple Mail Message from a VoodooPad Page
            Written by: Ken Clark
            Published on: January 21, 2013
            About this script: http://www.nineboxes.net/2013/01/an-applescript-to-create-an-apple-mail-message-from-a-voodoopad-page/
        *)
tell application "VoodooPad"
    tell front document
        set current_page to current page name
        set email_body to text of page current_page
    end tell
    tell application "Mail"
        set the_message to make new outgoing message with properties {subject:current_page, content:email_body, visible:true}
        activate
    end tell
end tell

Enjoy.

Transforming Text with Automator and Perl

Several years ago I wrote a blog post about naming files, and I explained my system for putting dates in filenames was as follows:

  • If I am putting a specific date in the file, I use (YYYY-MM-DD) format. For example: Staff Meeting Minutes (2009-01-18).doc.
  • If I have a document that is based on a month, I will use YYYY-MM, i.e. Staff Meeting Minutes (2009-01).doc; one that is based on a quarter – YYYY-QQ, i.e. Staff Meeting Minutes (2009-Q1).doc.
  • I put dates at the end of the file name and not the beginning purely based on my sorting preferences. I know that I am more likely to want to see groups of files with common topics first, and then dates second; rather than the opposite sort.

Recently, I’ve decided to modify my system as I have found there is more utility for me in having the date at the beginning of the file name, rather than the end. So, for example, that “Staff Meeting Minutes (2009-01-18)” file in my new methodology would instead be named “2009-01-18 – Staff Meeting Minutes”.

I plan to write a script of some sort to update my existing filenames to the new format, but in the interim I have been bumping up against VoodooPad notes that are named in the old format.1 After manually changing the names and wiki links for a half dozen pages, I took the time to write an Automator service to do it on the fly.

The service is simple, but a big timesaver. It receives text, passes it through a “Run Shell Script” action that invokes a Perl regular expression, and then outputs the filename, link or page name using my new date format.2

For example, when the service is invoked:

  • “Staff Meeting Minutes (2009-01-18)” becomes “2009-01-18 – Staff Meeting Minutes”
  • “Staff Meeting Minutes (2009-01)” becomes “2009-01 – Staff Meeting Minutes”
  • “Staff Meeting Minutes (2009-Q1)” becomes “2009-Q1 – Staff Meeting Minutes”

Additionally, if the text starts with a # or a *, as many links in my Markdown-based VoodooPad notes do, it carries that through. For example:

  • “# Staff Meeting Minutes (2009-01-18)” becomes “# 2009-01-18 – Staff Meeting Minutes”
  • “* Staff Meeting Minutes (2009-01-18)” becomes “* 2009-01-18 – Staff Meeting Minutes”

Here’s what it looks like in Automator:

A Service to Modify a Date Format in a Text String

I’ve also assigned a keyboard shortcut to the service via System Preferences. Additionally, given this service works on any type of text input, an additional benefit has been that it works great to rename files on the fly in the Finder.

If you’re working through a similar problem with updating strings of text, hopefully this gives you a few ideas on how to best tackle it. This has worked great for me.


  1. Yes, in retrospect, I could have made my life a little easier if I had thought of this before I imported these notes into VoodooPad! 

  2. Writing this service also provided me with an excuse to try out RegExRX, a Mac app for developing regular expressions. What a terrific app. As a spare-time scripter, at $4.99 it is a no brainer and huge time saver. 

An AppleScript to Create a VoodooPad Page from an Apple Mail Message

I have been having a great time recently exploring the in’s and out’s of VoodooPad. This week, I needed to copy the body of an email into VoodooPad, and just as I began the sequence of Command-A, Command-C, alt-tab, Command-N, Command-V, I I stopped myself. There had to be a better way.

I remembered that Shawn Blanc had written an AppleScript to send Mail to Yojimbo which automated a similar function for Yojimbo. His script was based on an AppleScript originally written by Jim Correia of Bare Bones Software.

Shawn’s AppleScript was easily adapted for VoodooPad. Here are the details:

  • The script targets the frontmost VoodooPad document.

  • It creates a VoodooPad page named after the subject of the selected email. If multiple messages are selected, they are concatenated into one note. (This could easily be changed if you wanted to create multiple notes for multiple emails.)

  • I added a title to the VoodooPad page based on the subject name, and I assume the destination format is Markdown. For example if the email subject was “How are you?”, the script inserts “# How are you?” as the first line of content.

  • Shawn’s script added a function to add tags in Yojimbo. I did not port this functionality for VoodooPad, as I don’t use tags for much at the moment.

  • I also removed Growl support as the script brings VoodooPad to the forefront once the page is added — which is the functionality I desired.

That’s it! Here’s the code:


    (* An AppleScript to Create a VoodooPad Page from an Apple Mail Message
            Written (well, actually modified…) by: Ken Clark
            Published on: January 10, 2013
            About this script: http://www.nineboxes.net/2013/01/an-applescript-to-create-a-voodoopad-page-from-an-apple-mail-message/
            Contributing Code:
            * There is very little original code in this script. I simply modified Shawn Blanc's "Mail to Yojimbo" AppleScript: http://shawnblanc.net/2009/08/mail-to-yojimbo-script/ to support VoodooPad instead of Yojimbo. Shawn's script was based on a similar script written by Jim Correia of Bare Bones Software.
            * I modified the script as follows:
                - replaced the code to create a Yojimbo note with code to create a VoodooPad page
                - removed tag support (I don't use tags very often in VoodooPad)
                - removed Growl support (as written VP will come to the forefront when the note is created so it was redundant for me)
                - formatted the note content to include a Markdown title, e.g. "# Subject of Email" 
        *)
    
    on generateMessageText(m)
        tell application "Mail"
            set _sender to sender of m
            set _subject to subject of m
            set _date to date received of m as string
            set _contents to content of m
            set _messageString to "# " & _subject & return & return
            set _messageString to _messageString & "From:" & tab & _sender & return
            set _messageString to _messageString & "Subject:" & tab & _subject & return
            set _messageString to _messageString & "Date:" & tab & _date & return
            set _messageString to _messageString & return & _contents
        end tell
    end generateMessageText
    
    on run
        tell application "Mail"
            tell message viewer 1
                set messageList to selected messages
                set _name to subject of item 1 of messageList
                set _contents to ""
                repeat with m in messageList
                    set _contents to _contents & my generateMessageText(m)
                    set _subject to subject of m
                    set _date to date received of m as string
                end repeat
                
                -- create the new note
                tell application "VoodooPad"
                    activate
                    tell document 1 to create new page with name _name with content _contents
                end tell
                
            end tell
        end tell
    end run

TextExpander Snippets to Create Implicit Markdown Reference-Style Links

These are the TextExpander snippets I use to create Markdown links. I almost always create reference links with implicit link names instead of inline references, so all of these, except the last, support that style.

Create an inline link with implicit link name

As basic as it gets. Create an implicit link with the cursor positioned within the link name.

Content Type: Plain text
Snippet Content:

[%|][]

Abbreviation: md[

Create an inline link with implicit link name from the title of the frontmost Safari document

Content Type: AppleScript
Snippet Content:

tell application "Safari" to set theTitle to name of front document
set markdown_string to "[" & theTitle & "][]”

Abbreviation: mdim
Example:

If Daring Fireball was the frontmost document in Safari, this would generate:

[Daring Fireball][]

Create a link definition from the title and URL of the frontmost Safari document

I use this in conjunction with the snippet above. I use this to automatically generate the implicit link definition.

Content Type: AppleScript
Snippet Content:

tell application "Safari"
    set theTitle to name of front document
    set theURL to URL of front document
end tell
set markdown_string to "[" & theTitle & "]:" & theURL

Abbreviation: mddef
Example:

If Daring Fireball was the frontmost document in Safari, this would generate:

[Daring Fireball]:http://daringfireball.net/

Create an inline link with implicit link name from the clipboard

Content Type: Plain text
Snippet Content:

[%|][]

Abbreviation: mdc
Example:

If "John Gruber's Website" was copied to the clipboard, this would generate:

[John Gruber's website][]

New implicit link definition with implicit link name from the clipboard

I use this one when I have text of the reference in the clipboard, but I want to manually enter the URL. Cursor is positioned after the colon.

Content Type: Plain text
Snippet Content:

[%clipboard]:%|

Abbreviation: mddeft
Example:

If "John Gruber's Website" was copied to the clipboard, this would generate:

[John Gruber's Website]:

Create a link definition with the title from the clipboard and the URL of the frontmost Safari document

I use this when I have written a custom link name to the frontmost Safari website. Once I write the link name, I copy it to the clipboard, and then use this snippet to generate the link definition.

Content Type: AppleScript
Snippet Content:

set theTitle to the contents of (the clipboard)
tell application "Safari" to set theURL to URL of front document
set markdown_string to "[" & theTitle & "]:" & theURL

Abbreviation: mddec
Example:

If "John Gruber's website" was copied to the clipboard and Daring Fireball was the frontmost document in Safari, this would generate:

[John Gruber's website]:http://daringfireball.net/

Create a link definition with no title and the URL of the frontmost Safari document

This is a variation of the above. It pulls the URL from Safari, but leaves a blank link name. I might use this if I'm creating the reference URL before putting the reference in the document or if I haven't copied the link name to the clipboard.

Content Type: AppleScript
Snippet Content:

set theTitle to the contents of (the clipboard)
tell application "Safari" to set theURL to URL of front document
set markdown_string to "[]:" & theURL

Abbreviation: mddeb Example:

If Daring Fireball was the frontmost document in Safari this would generate:

[]:http://daringfireball.net/

Create an inline reference with the title of the frontmost Safari document

This is the only snippet I've included that uses the inline style, so if you use this style it is pretty helpful.

Content Type: AppleScript
Snippet Content:

tell application "Safari"
    set theTitle to name of front document
    set theURL to URL of front document
end tell
set markdown_string to "[" & theTitle & "](" & theURL & ")"

Abbreviation: mdin
Example:

If Daring Fireball was the frontmost document in Safari this would generate:

[Daring Fireball](http://daringfireball.net/)

An AppleScript to Import Yojimbo Notes into VoodooPad

I am giving VoodooPad a run as my “everything bucket” and wrote an AppleScript to import my 500+ Yojimbo notes into my VoodooPad notebook. If you are looking to do something similar, this script may be of help or at least a good place to start.

Here’s how it works:

  • The script targets the frontmost VoodooPad document.

  • It creates a VoodooPad page for every imported Yojimbo note. I wrote the script assuming the VoodooPad New Page Format preference was set to Markdown, so I never tested RTF as a destination format. However, I believe RTF to RTF should work fine.

  • It also creates an index page in VoodooPad with VoodooPad links to all imported notes. This index is formatted using Markdown syntax and will be named “Imported Yojimbo Notes” by default. The name can be customized via the import_name variable.

  • By default the script will import all notes from the Yojimbo library into VoodooPad using the Yojimbo note name as the VoodooPad page name. However, there are a few lines in the script that allow you to tweak this behavior:

    1. You can modify the main repeat loop to either pull all notes in the Yojimbo library or only certain notes based on a given criteria. The example in the script is a name search, but it could be any scriptable criteria.

    2. I used Bruce Phillips’ search and replace AppleScript function to provide an option to remove or replace text from certain titles. Note: this is commented out in the example script.

    3. I used Qwerty Denzel’s AppleScript modify case functions to provide an option to change the case of the note titles going into VoodooPad. Note: this is also commented out in the example script.

  • Once the import is done, it does not delete the notes in Yojimbo, but instead tags them with “@imported to VoodooPad”.

Enjoy.

(* An AppleScript to Import Yojimbo Notes into VoodooPad
        Written by: Ken Clark
        Published on: December 31, 2012
        About this script: http://www.nineboxes.net/2012/12/an-applescript-to-import-yojimbo-notes-into-voodoopad/
        Contributing Code:
        * Search and Replace AppleScript code by Bruce Phillips: http://foolsworkshop.com/applescript/2008/05/an-applescript-replace-text-method/
        * AppleScript text case functions by Qwerty Denzel: http://macscripter.net/viewtopic.php?id=13297 
    *)

property alphaList : "abcdefghijklmnopqrstuvwxyz"'s items & reverse of "ABCDEFGHIJKLMNOPQRSTUVWXYZ"'s items
set import_name to "Imported Yojimbo Notes" -- the name of the VoodooPad index page for the imported notes. 
set import_index to "# " & import_name & "

    "
tell application "Yojimbo"
    -- Note: The script includes two examples for looping through Yojimbo. The first (commented) repeat loop only selects notes that start with a particular phrase. The second (uncommented) repeat loop gets all notes in the Yojimbo library. You can modify the syntax of these repeat loops to select notes on other criteria based on your needs.

    -- Example one: get every note in the Yojimbo library that starts with a given term or phrase
    -- repeat with y_item in (every note item in library whose name starts with "enter text here")

    -- Example two: select every note in the Yojimbo library (default)
    repeat with y_item in every note item in library
        set item_name to the name of y_item
        set item_contents to the content of y_item
        -- Note: this block is commented out by default as you would only use it if you want to manipulate the name of the Yojimbo item before it goes into VoodooPad. 
        (*tell me
                -- Option one: this line will replace certain phrases in your titles before the import. This example removes "Applescript:" from titles of notes.
                set item_name to replaceText("AppleScript: ", "", item_name)
                -- Option two: this line will title case all note names before the import.
                set item_name to changeCase of item_name to "title"  
            end tell*)
        set page_content to "# " & item_name & "

    " & item_contents
        tell application "VoodooPad"
            tell document 1 to create new page with name item_name with content page_content
        end tell
        set import_index to import_index & "* " & item_name & "
    "
        -- This adds a "@imported to Voodoopad" tag to every Yojimbo note that was imported into VoodooPad. Comment this out if you don't want that. 
        add tags "@imported to VoodooPad" to y_item
    end repeat
end tell

-- Create import index
tell application "VoodooPad"
    tell document 1 to create new page with name import_name with content import_index
end tell

-- ** Subroutines **

-- ReplaceText function by Bruce Phillips
on replaceText(find, replace, subject)
    set prevTIDs to text item delimiters of AppleScript
    set text item delimiters of AppleScript to find
    set subject to text items of subject

    set text item delimiters of AppleScript to replace
    set subject to "" & subject
    set text item delimiters of AppleScript to prevTIDs

    return subject
end replaceText

-- Modify Case with AppleScript by Qwerty Denzel
on textItems from t
    try
        t's text items
    on error number -2706
        tell (count t's text items) div 2 to my (textItems from (t's text 1 thru text item it)) & my (textItems from (t's text from text item (it + 1) to -1))
    end try
end textItems

to changeCase of t to c
    if (count t) is 0 then return t
    considering case
        if c is not in {"upper", "lower", "title", "sentence"} then
            error "The word \"" & c & "\" is not a valid option. Please use \"upper\", \"lower\", \"title\" or \"sentence\"."
        else if c is "upper" then
            set n to 1
        else
            set n to -1
        end if
        set d to text item delimiters
        repeat with n from n to n * 26 by n
            set text item delimiters to my alphaList's item n
            set t to textItems from t
            set text item delimiters to my alphaList's item -n
            tell t to set t to beginning & ({""} & rest)
        end repeat
        if c is in {"title", "sentence"} then
            if c is "title" then
                set s to space
            else
                set s to ". "
            end if
            set t to (t's item 1 & s & t)'s text 2 thru -1
            repeat with i in {s, tab, return, ASCII character 10}
                set text item delimiters to i
                if (count t's text items) > 1 then repeat with n from 1 to 26
                    set text item delimiters to i & my alphaList's item n
                    if (count t's text items) > 1 then
                        set t to textItems from t
                        set text item delimiters to i & my alphaList's item -n
                        tell t to set t to beginning & ({""} & rest)
                    end if
                end repeat
            end repeat
            set t to t's text ((count s) + 1) thru -1
        end if
        set text item delimiters to d
    end considering
    t
end changeCase

Simplifying

I have always taken pride in being a technology power user. I’m the type of guy who experiments with and tweaks my technology workflows in an effort to get things done in the most efficient way possible.

So it has been frustrating of late to see a growing trend of complexity in much of what I do. How do I decide when to save my documents to iCloud, Dropbox, or my local hard drive? Is that AppleScript I wrote to “simplify” a workflow really the easiest way to get it done? Why do I have multiple places where I store my bookmarks? My notes? My photos?

Some of this is of my own making. I can be guilty of over-complicating things despite my best intentions to make things more elegant. However, that’s not the whole story. I’m also wrestling with the right strategies for when and how to sync data across multiple devices and cloud services.

I’ve realized that I need to take a new look at my workflows, both big and small. I’m going to use these questions as my guide:

1) Can this be made simpler?
2) Have I eliminated any points of friction that would, consciously or subconsciously, deter me from doing my work?
3) Does this work equally well across Macs, iOS devices, and the web? If no, am I ok with that?
4) Do I really need this app / script / web service / device?

The objective is to make my workflows as simple as possible, or to phrase it a little differently, ensure they are only as complex as they need to be.

Time to get to work.

New Robotic Legs Recreate Human Gait – Forbes »

Scientists at the University of Arizona yesterday published research on the development of a two-legged robot designed to accurately mimic the  gait patterns of human beings.

It’s impressive enough that the robot moves like a person, courtesy of motors that push-and-pull on artificial leg “muscles” made of kevlar straps. But the robots are also endowed with sensors (including load sensors in the feet and on each muscle strap) and a computerized version of a specific human neural network, known as the central pattern generator (CPG), that stabilizes leg movement and allows humans to walk rhythmically.

More evidence that Skynet is coming.

Brent Simmons on How to Build an “Independent Twitter” »

Brent Simmons:

Were I a Twitter client developer, I would get in touch with other client developers and start talking about a way to do what Twitter does but that doesn’t require Twitter itself (or any specific company or service).

Once we came to a consensus, then we’d add support for whatever-it-is to our apps. We wouldn’t drop Twitter support — we’d just add the new thing. Do both.

And then we’d promote the new thing, encourage people to use it, help it grow. Then drop Twitter some day — or wait till Twitter cuts off our apps. Whatever. And not care, because we’ve got the new thing.

Brent goes on to explain how a lot of this could be done on the back of RSS and OPML. There’s a very cool idea here. I’d love to see a group run with it.