Opening a Finder’s window from Impromptu (alas how to use the applescript bridge..)

Imagine you’ve got a bunch of audio samples you want to load up while livecoding with Impromptu but you can’t remember exactly their names – it’d be handy to be able to open up the corresponding Finder window directly from scheme, without too much clicking around. Do-able or not?

I spent some time trying to figure this out, and the answer is yes! Quite a nice learning experience… although it came with a surprise at the end.

Originally I thought, let’s do it via impromptu’s ObjC bridge. I don’t know much about ObjC but after a bit of googling it seemed evident that the quickest way to accomplish this is by writing ObjC code that, in turns, runs a simple applescript command that opens a window:


NSString *s = [NSString stringWithFormat:
     @"tell application "Terminal" to do script "cd %@"", folderPath];

NSAppleScript *as = [[NSAppleScript alloc] initWithSource: s];
[as executeAndReturnError:nil];


So I translated the bottom part of the code above into impromptu/scheme:


(define run_applescript
   (lambda (script)
      (objc:call (objc:call (objc:call "NSAppleScript" "alloc")
                 "executeAndReturnError:" )))


That is a generic script-running function, that is, you can pass any script and it’ll run it, eg:


(define script0 "
   tell application "Finder" to open folder "Macintosh HD:Users"
   tell application "Finder" to activate"

(define script1 "
   tell application "Terminal" to do script "cd ~; open .""

(define script2 "
                tell application "System Events"n
                tell dock preferencesn
                set properties to {autohide:false}n
                end telln
                end tell"

;; finally, let’s choose randomly one of the scripts above and run it
(run_applescript (random ‘(script0 script1 script2)))


Now, back to the original problem: in order to open a Finder’s window at a specified location we need to pass the location variable to our function run_applescript; also, we want to be able to pass unix path expressions (eg ‘/Users/mike/music/’), so we’ve got to transform that path syntax into the semicolon-delimited macintosh syntax (“Macintosh HD:Users:mike:music”) needed by the applescript function we’re using. That’s easily done with string-replace, so here we go:


(define open_finder_at
   (lambda (location)
      (let* ((llocation (stringreplace location "/" ":"))
              (script (string-append "tell application "Finder" to activate open folder "Macintosh HD" llocation """)))
         (objc:call (objc:call (objc:call "NSAppleScript" "alloc")
                    "executeAndReturnError:" ))))

(open_finder_at "/Users/me/")


That’s pretty much it really… now we can easily open OsX Finder’s windows from within Impromptu.

But as I said above, there’s a surprise: after getting this far I thought I’d search impromptu’s mailing list for more examples of obj:call …. and guess what, there’s already a system function that runs applescripts, it’s called sys:run-applescript !

Too bad, it’s been a rewarding learning experience anyways…



Comments are closed.