MACRO Example: Swift Script returning list of variable names from KME

FWIW this seems to work as a 'Hello World' for OSAKit in Swift:

List KM variables from Swift through OSAKit.kmmacros (18.3 KB)

import OSAKit

func evalOSA(code: String) -> NSAppleEventDescriptor? {

    var error: NSDictionary?
    let oScript = OSAScript(
        source: code,
        language: OSALanguage(forName: "JavaScript")
    )

    return oScript.executeAndReturnError(&error)
}

let s = evalOSA("Application('Keyboard Maestro Engine').variables()" +
                ".map(function (x) { return x.name(); }).join('\\n')")
if s != nil {
    print(s!.stringValue!)
}

Cool. Running AS is just as easy:

import Foundation

let _script = "\"Hello World\""

var error: NSDictionary?
if let scriptObject = NSAppleScript(source: _script) {
	if let _descriptor: NSAppleEventDescriptor = scriptObject.executeAndReturnError(&error) {
		print(_descriptor.stringValue!);
	}
	else if (error != nil) {
		print("error: \(error)")
	}
}

Looks like there’s lots of ways to do this.

Too bad the code for eliminating JXA or AS completely is too slow to compile. But this isn’t horrible.

I guess a couple of simple functions for reading and setting Keyboard Maestro variables from Swift could be neatly wrapped and need only very minimal snippets of JS/AS.

At this point, Swift has disadvantages, because I need to call JXA or AS to talk to KM. I can do it without that, but it compiles way too slow.

For advantages, it's just that it's a language I feel really comfortable with. I still have stuff to learn, but it's fairly easy for me to pick up, because it's so much like C#. The IDE (Xcode) is pretty good. Debugging and everything else all integrated. Oh - and code folding! Man how I missed that.

And if you ever need to view the contents of a plist file or .kmmacros file, open it with Xcode. Not bad.

Most everything I learn with Swift can be used directly to write OS/X apps or iOS apps. Well, the iOS apps use different libraries, but the language is the same.

Swift is the kind of language that is well-suited for building large applications, with lots of classes and modules. Wouldn't want to do that in JS - it's possible, but that's not really what JS is for. And certainly not what AS is for.

As far as scripting is concerned, other than the automation issue, it's a "what do you feel most comfortable with" situation.

Oh absolutely. Right now it’s easy to deal with a string result, but anything else is uncharted waters. I’m working on some code to parse other types of results, but it’s not as simple as you might think - on the other hand, it may just be lack of knowledge.

I’ve got this:

func parseDescriptor(desc: NSAppleEventDescriptor)
{
	let _descType: Int = Int(desc.descriptorType);
	
	switch ( _descType ) {
	case typeUnicodeText,
	     typeUTF8Text:
		print("Text >\(desc.stringValue)<");
	case typeFileURL:
		print("FileURL >\(desc.fileURLValue)<");
	case typeAEList:
		print("List")
	//		object = [NSArray scriptingUserListWithDescriptor:self];
	case typeAERecord:
		print("Record")
	//		object = [NSDictionary scriptingUserDefinedRecordWithDescriptor:self];
	case typeSInt16,
	     typeUInt16,
	     typeSInt32,
	     typeUInt32,
	     typeSInt64,
	     typeUInt64:
		print("Int: \(desc.int32Value)");
	default:
		print("Unknown type");
		//		// create NSData to hold the data for an unfamiliar type
		//
		//		bigEndianDescType = EndianU32_NtoB(descType);
		//		NSLog(@"Creating NSData for AE desc type %.4s.", (char*)&bigEndianDescType);
		//		object = [self data];
	}
}

I’m trying to figure out how to parse a list of records. But it’s on the back-burner right now, because I can encode whatever I need in a string, with tabs or other delimiters, so I can probably do anything I need with strings.

But I’m also the type of person who wants things the way I want them. So we’ll see.

@ComplexPoint - Want a challenge? I want some way to parse a KM “Calculation” field to get all variable names in it, if any.

Some examples:

  • “My Variable MOD 20 = 0” would return “My Variable”
  • “Variable 2 + 3” would return “Variable 2”
  • “Variable - 2 + 3” would return “Variable”
  • “MIN(Variable1, Variable 2)” would return “Variable1” and “Variable 2”

You get the idea. Some of the permutations can get downright scary.

Well, the proper way to do that might be to generate a parser from some kind of PEG tool – I’m not sure that a piecemeal attack would give you a very good ratio of effort to reward.

You would, however, have to specify the grammar. Isn’t there a way of using Peter’s existing parser ?

If you’re sure you want to experiment with it, then PEG.js is the first thing that comes to mind:

http://pegjs.org/
http://nathansuniversity.com/pegs.html

I hear you. If it comes to it, I can skip Calculation fields entirely. Since my goal is to find variables used in a macro, chances are pretty good that if you reference a variable in a Calculation field, you probably used it somewhere else in the macro, typically to set it somehow.

Nope. I asked. :slight_smile:

This is totally cool. It's also not something I'm capable of using, but Peter certainly could - not that he'd need it of course - he mentioned that he's written OSes before.

Hey @peternlewis, in your spare time, want to take a stab at creating a Peg.js rule set for parsing your Calculation fields to get the names of variables? What, you don't understand the phrase "spare time"? (A little joke here - I'm sure you're way to busy for this. Thought you might appreciate the joke, though. Or... perhaps not.)

Not really, no.

1 Like

I was pretty-much kidding, by the way. I wouldn’t really want to take your focus away from more important things.

I probably shouldn’t even have said it, except I thought there was a chance it might trigger something in your mind, like “Oh yeah, I’m using such-and-such standard ruleset, try searching for that”.

Hope I didn’t tick you off. My sense of humor is an acquired taste.

Hi All,

I am looking for a method to extract all variable names of a certain macro or all macros.

The search engine take me to this post, but I don't quite understand what's talking about here.

So my question is that is there a macro can list all the variable names used in a macro selected in KM editor? or used in all my macros?

Does this post talked about this?

Try his Get List of KM Variables and Size @KM @Tool

I was just being touched. He's still the man. We still need him. Many thanks.

Have a look at this then: MACRO: Variable Inspector Prompt and Dictionary Editor v3.2

They are all genius works. But they all focus on global vars. But learned from many articles on this forum, the total number of global vars was strictly controlled. I dont use global vars as possible as I can. That means most of the var names I want to check is Instance__ or Local__.
And I am not coder, how to modify these macros to get what I want is difficult. Since these macros are too professional to read for m e :joy: :sob: :sob: :sob:

The Variable Inspector Prompt shows local variables too - just read the instructions on how to use it.

I tried, but the language they use is really hard for me to read. I need more time to learn that.

Many thanks.

Another option besides VIP:

I haven't used either one and therefore have no opinion on their efficacy (yet).

1 Like

Installing the Variable Inspector Prompt (VIP) utility is easy - just download and unzip the file and then double-click to install into KM.

You then include the following action in your own macros:

image

When you run your macro the VIP shows something like this:

This is a test macro of mine and you can see it has global, instance and local variables displayed.

Just make sure the VIP options are set up correctly like this for example:

2023-03-22_18-46-42

I'm not sure how else I can help so I hope you can make some progress!

3 Likes

Many thanks. Really appreciate it. Let me do the last thing.

1 Like