DEV Community

Khoa Pham
Khoa Pham

Posted on

Calling function inside Apple Script

Original post https://github.com/onmyway133/blog/issues/88

I 've been using Apple Script to for my Finder extension FinderGo. Because of sandboxing, all scripts must lie inside Application Scripts folder.

Today, I was rewriting my Xcode extension XcodeWay. Before Xcode 8, we could use Xcode plugin and all kinds of magic to make our dreams come true https://github.com/onmyway133/XcodeWay/blob/1.0/XcodeWay/Helper/FTGEnvironmentManager.m#L50. But then it does not work since Xcode Source Editor Extension was introduced. So I rewrote XcodeWay as an extension https://github.com/onmyway133/XcodeWay/releases/tag/1.1.0

Extension must run inside sandbox. If you switch App Sandbox in your XcodeWayExtensions.entitlements to NO, it won't load. So sandbox restricts me a lot in what kinds of things I want to do. And under Xcode 9, I can't use NSWorkspace to open Finder.

So I think I could use Apple Script too, and it worked like a charm. The only restriction is code reuse, since I only know how to run an entire script. One way is to import other Apple scripts https://stackoverflow.com/questions/2606136/import-applescript-methods-in-another-applescript but I think I will write all the functions inside 1 script, and find out how to call specific function.

By function, I also mean handler, procedure. I come across this snippet Scriptinator that pretty much inspires me, thanks to open source.

So here is my script that contains lots of functions . And here is ScriptRunner that explains how to build NSAppleEventDescriptor. Note that you need to import Carbon

import Carbon

func eventDescriptior(functionName: String) -> NSAppleEventDescriptor {
  var psn = ProcessSerialNumber(highLongOfPSN: 0, lowLongOfPSN: UInt32(kCurrentProcess))
  let target = NSAppleEventDescriptor(
    descriptorType: typeProcessSerialNumber,
    bytes: &psn,
    length: MemoryLayout<ProcessSerialNumber>.size
  )

  let event = NSAppleEventDescriptor(
    eventClass: UInt32(kASAppleScriptSuite),
    eventID: UInt32(kASSubroutineEvent),
    targetDescriptor: target,
    returnID: Int16(kAutoGenerateReturnID),
    transactionID: Int32(kAnyTransactionID)
  )

  let function = NSAppleEventDescriptor(string: functionName)
  event.setParam(function, forKeyword: AEKeyword(keyASSubroutineName))

  return event
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)