Cross-play between Script Debugger and Script Editor

While looking into something with Script Editor this morning, I happened to notice the additional item “AppleScript Debugger” in its language-selection pop-up. Wondering if it might be a new feature, I selected it and tried running the script beep, which ran for several seconds doing nothing until I typed Command-. to stop it. Immediately, a dialog appeared saying: “AppleScript debugging failed because Script Debugger is not available on this Macintosh”.

When I tried it with Script Debugger open, Script Debugger came to the front with the script showing in a new tab, its first line shaded green. Typing Command-r ran the script in Script Debugger, whereupon the tab immediately closed and the script stopped running in Script Editor.

Is this confusion between the two applications supposed to happen?

It’s been this way for a long time, if not forever. The language popup shows all installed OSA languages (presumably calling OSALanguage’s +availableLanguages), but that doesn’t mean it can use them properly.

What you’re seeing is a bit like saving a script in debugging mode and running it from a host other than Script Debugger, such as FastScripts or an app that has a Scripts menu.

1 Like

Hi Shane. Thanks for that.

A related question to that. I want to determine the OSA language from the command line, but I can’t find a command for that.

The only thing I could come up with is in AppleScript to open the file with Script Editor and then query the language property of the document. I scripted that, but because it relies on Script Editor, every time you run the script you get an GUI flash (plus it is not really that fast).

Any solutions?

Is this of any help ?

use AppleScript version "2.4"
use framework "Foundation"
use framework "OSAKit"

set sourceFile to (current application's NSURL's fileURLWithPath:"/posix/path/toScriptfile")
set {theScript, theError} to current application's OSAScript's alloc()'s initWithContentsOfURL:sourceFile |error|:(reference)
if theScript = missing value then error (theError's localizedDescription()) as text
return theScript's language()'s |name|() as text

As Shane describes, this is intended behaviour (though Mac OS security changes seem to prevent the automatic launching of Script Debugger).

This is a feature called external debugging. It allows you to debug scripts directly within the their intended runtime environment. This is useful when you need to debug even handlers that cannot be easily simulated within Script Debugger its self.

Hi Mark. Thanks for the additional information.

That’s it! I knew there was something like OSAKit, but I couldn’t find the documentation. And my Objective-C/Swift skills are not very strong :smiley:. Big thanks!

There’s one problem though. When I save a .scpt script with the debugging option switched on, it raises an error on scripts saved in AppleScript Debugger format. theScript is missing value, but theError doesn’t seem to have a ‘localizedDescription’ method.

The line error (theError's localizedDescription()) as text results in the error:

[__NSFrozenDictionaryM localizedDescription]: unrecognized selector sent to instance 0x60400043d3c0

AFAIK, there’s no documentation on OSAKit.

If I’m not wrong, Applescript Debugger is not part of Apple’s Applescript but an addition from Script Debugger.
@alldritt ( or @ShaneStanley) has certainly the answer…

Yes, there’s a problem in @ionah’s script: perversely, the error parameter in this case returns an NSDictionary, not an NSError. If you just want to see what it contains, change localizedDescription to |description|. Otherwise the keys used, some of which are optional, are listed at the top of OSAScript.h.

The statement (theError's description) as record returns the following:

  • from: NSDictionary
    • OSAScriptErrorNumberKey: NSNumber -2147450879
  • «class form»: «constant ****prop»
  • «class seld»: description
  • «class want»: property

I’m not sure what this means though.

However, the problem is that OSAScript's alloc()'s initWithContentsOfURL: fails to load an .scpt file in AppleScript Debugger format. TextMate’s decompile_as also fails to decompile AppleScript Debugger format (this will hopefully soon be solved by using osadecompile which was introduced in OS X 10.4).

Maybe some extra initialization has to be done to use non-standard languages. However, browsing through the header-files of OSAKit I don’t see any clues…

You want either theError's |description|() as text or theError as record.

You have to use one of the other methods, first creating a language instance. it depends what you want to do, exactly.

If you want to find out the language, you use the class method scriptDataDescriptorWithContentsOfURL: to make a descriptor, and then use the OSALanguage class method languageForScriptDataDescriptor:. You can then create a suitable instance, and use initWithScriptDataDescriptor:fromURL:languageInstance:usingStorageOptions:error:.

I now have this:

	use AppleScript version "2.4"
	use framework "Foundation"
	use framework "OSAKit"

	set scpt_path to "/Users/doeke/Downloads/asdbg.scpt"
	set sourceFile to (current application's NSURL's fileURLWithPath:scpt_path)
	set sourceDescriptor to (current application's OSAScript's scriptDataDescriptorWithContentsOfURL:sourceFile)
	set sourceLanguage to (current application's OSALanguage's languageForScriptDataDescriptor:sourceDescriptor)

However, when scpt_path points to an AppleScript Debugger formatted file, sourceLanguage contains missing value. With an AppleScript or JavaScript .scpt-file, it’s pointing to an existing object.

All I want to do is find out the language of an .scpt-file…

Considering that a .scpt file can only contain a compiled script, here is my solution:

use AppleScript version "2.4"
use framework "Foundation"
use framework "AppKit"
use framework "OSAKit"
use scripting additions

set theURL to current application's NSURL's fileURLWithPath:"/Users/me/Desktop/Script.scpt"
	
set theScript to current application's OSAScript's alloc()'s initWithContentsOfURL:theURL |error|:(missing value)
	if theScript = missing value then
		set {theScript, theError} to current application's NSAppleScript's alloc()'s initWithContentsOfURL:theURL |error|:(reference)
		if theScript = missing value then error "File or contained Script is unreachable"
		return "Applescript Debugger"
	end if
	
return theScript's language()'s |name|() as text

This code first tries to get the script contained in the file using OSAScript and if it fails, tries with NSAppleScript and finally returns an error if it can’t find any valid source.

Add one more line?

set langName to sourceLanguage's |name|()

when scpt_path points to an AppleScript Debugger formatted file, sourceLanguage contains missing value

That’s cos it’s probably not in the list of Available Languages. Although it shows up in the drop down menu of Script Editor, it doesn’t appear to be registered as an available language:

set availableLanguages to current application's OSALanguage's availableLanguages()
set langList to {}
repeat with lang in availableLanguages
	set end of langList to lang's |name|()
end repeat
langList

That returns only AppleScript and JavaScript here.

That’s given you the three known possibilities. I’m a bit surprised the script doesn’t work as I described, but this is AppleScript.

Thanks for sharing that, Jonas.

I’ve been looking for a way to determine whether to open a .scpt file with SD6 (AppleScript) or SE (JavaScript). This does the trick! :+1:

It’s too bad that the macOS can’t do this for us, so that a double-click would open the proper app. Any ideas about this?

It’s been several years since I used double-clicking in the Finder to open a script file.
I’m using scripts triggered by shortcuts: a first to open a script or an applet with SD, another to open a dictionary with SD and a third to open a script or an applet with SE.

Hey JM,

The only way I know of is via a 3rd party preference pane called Magic Launch.

I tried it out long ago, and there were things I didn’t like about it. If memory serves the main thing was that all open-with menus were polluted with MagicLaunchAgent, or some such.

The least intrusive method is to use a key-driven macro (as @ionah mentions).

I use LaunchBar a lot for this sort of thing, but then I have to know which app to launch in.

I just tested, and the .jxa suffix opens in the Script Editor — and FastScripts will run the .jxa suffixed script with no problem.

-Chris

Or maybe use an extension of your own: something like .javascpt or .jvscpt.
The advantage is that .jxa files will continue to act as they should.