JavaScript/JXA Editing and the Atom Editor

Oh, and I haven’t touched BBEdit in months, except for a Text Factory.

Don’t miss the code folding features.

Thanks for providing this, Dan. I've had installing Atom on my todo list for a while now, just can't seem to find a block of time to devote to it. Your instructions will help a lot.

Any idea how many hours it took to you starting install, to begin using Atom?

With the information I presented, it won't take you long at all. For me, I had to find all that crap, so it took a while. I kept giving up.

But you have me as a resource. So for you, it should go quickly. You should be able to get up and running in under an hour easily, I would think. How long it takes from there depends on how much time you spend trying to get it exactly the way you want. :slight_smile:

3 Likes

Many thanks for this.

I'll open an Evernote Note and keep a log of what I do.
Anything in particular you want me to capture?

Hey JM,

Maybe a half hour (or a little less) including all the package installs.

-Chris

Just what anyone else would wonder about.

By the way, you'll want to install the package linter-jshint, and follow the instructions in this note, above.

This is something you'll end up turning on and off as you work. But it's invaluable in helping catch errors, and also to teach you "proper" JavaScript (not that I know "proper" JavaScript but I'm learning, especially with tools like this).

And I find the package "command-toolbar" to be great for things like being able to toggle linter on and off. (I have it configured along the top, instead of the side):

1 Like

##Atom Multi-Selections

You may have noticed that when you select a word, other occurrences of the word are highlighted:

The one that is actually selected (the top one in this instance) looks slightly different.

Did you know you can have multiple selections? Hold down and double-click one of the other matching words, and now you've selected both of them:

You can continue selecting other matching words.

So what good is this? You can change all selected matches at once. For example:

The trick is, you can only use your keyboard. Don't click anywhere, or it will un-select everything.

###Column Multi-Selections:

(Not sure if my keymapping is the same as yours, so you may have to experiment.)

If I hold down ⇧⌃ and use the arrow keys, I can select multiple columns. Any changes made will affect all selected columns.

3 Likes

I am missing something here. A brief example file would help. I have been using Atom to execute code in other languages, including AppleScript, but I can’t get even alert("OK") to work using JS or JXA grammar. I have many packages installed, and I’ve made the change to linter-jshint you showed above.

Where does the JavaScript context come from when executing in Atom? How does it know about Objc, $, etc.?

I think these are the packages required, along with the version numbers I’m using:

build 0.67.0
language-javascript-jxa 0.2.8
script 3.13.0

I suspect you’re missing the language one. I think it’s the way Atom knows what to do when you try to run JXA-grammar files.

Let me know if this helps.

Here’s a script example that should help:

(function(inDesignMode) {
    'use strict';

    function execute() {
        var kme = Application("Keyboard Maestro Engine");
        var lastResultButton = kme.getvariable("Result Button");
        console.log("Last 'Result Button' value: '" + lastResultButton + "'");

        var app = Application.currentApplication();
        app.includeStandardAdditions = true;
        var appSupportPath = app.pathTo('application support', { from: 'user domain' });
        console.log("App support path: '" + appSupportPath + "'");


        var nsError = $();
        var contents =
            ObjC.deepUnwrap(
                $.NSFileManager.defaultManager.contentsOfDirectoryAtPathError(
                    $(appSupportPath + "/").stringByStandardizingPath, nsError)
            );
        if (!contents)
            throw Error($(nsError.localizedDescription).js);
        console.log("Contents of '" + appSupportPath + "':\n" + contents.join("\n"));

        return "OK";
    }

    if (inDesignMode) {
        return execute();
    } else {
        try {
            return execute();
        } catch (e) {
            return "Error: " + e.message;
        }
    }
})(true);

Here’s what it shows:

  1. Fully-enclosed script (surrounded by parens).

  2. I usually code bottom-up, so the first lines executed are at the end. Sort-of.

  3. The “if” and “try/catch” at the bottom is how I code things:

  • When running from Atom, I pass “true” in the last line, and when running in a KM action, I pass “false”, so I can test the variable “inDesignMode” to know which environment I’m running in.

  • My code makes sure that, when running not-inDesignMode, the script always returns “OK” if there are no errors, and always returns something starting with “Error:” if there are errors. Makes it easy to check the results.

  • When running inDesignMode, the errors show line numbers. They don’t show line numbers otherwise.

  1. Uses a KM function.

  2. Uses a “standard additions” function.

  3. Uses an .NSFileManager function.

Hope this helps.

That‘s an excellent example, with many important basic maneuvers demonstrated! Many thanks. (Having this example somewhere very obvious would save a great deal of mucking around for anyone approaching JXA for the first time, especially people who are intimidated by the idea.

It would be nice if there were a category for example scripts — not scripts that do interesting or elaborate things, but scripts that are designed to demonstrate how to do various things in the various scripting languages. Yes I know that the JXA Cookbook cited in the next paragraph has some of this for JXA, but I don't know where to find such things for the other languages. I just do a lot of Googling, and collect good starting points. (See my Website Popups Using Automator, also known as Open Standalone Web Pages — Great for References.)

I've got my trivial alert script untangled. The problem is that there is no alert! (See User Interactions · dtinth/JXA-Cookbook Wiki for information on programming dialogues in JXA.) Here‘s what my successful script looks like now:

var app = Application.currentApplication();
app.includeStandardAdditions = true
app.displayAlert("atom.js");

I still don’t understand who is running the script (context).

I also don‘t understand how Atom knows to run this as JXA and not JavaScript or node.js. I did do the Edit | Select Grammar menu command — do you think that’s enough for Atom’s script package to know what to do?

I'm working on getting a new website running, and one of the things I will be doing is what you're asking for. I just keep getting sidetracked, but it will happen.

I still don’t understand who is running the script (context).

In Atom, go to Settings, then select Packages:

Put your cursor over "language-javascript-jxa", and click. It takes you to the support page for the package. And while there's only limited information there, you will discover this tidbit:

That's as much as I know.

Mitchell -

I was just thinking. One thing my JXA example script didn't make clear:

As written, it returns either "OK" or "Error:". But really, all that's required is "Error:". So you can actually return something meaningful when the result isn't an error.

Example:

The JXA script runs and returns the result in 'ScriptResult'.

If ScriptResult starts with "Error:", then an error occurred.

Otherwise, ScriptResult contains whatever you returned from the script. "OK" isn't very useful, but obviously you could return anything.

You can of course use something different than "Error:" to report an error, but I can't think of many situations where a non-error response from a script would start with "Error:", so this works.

Hope that helps.

Feel free to hit me up with questions, if you've got them. Either on the forum or via PM.

I use a very similar approach. The only difference is that I use "[ERROR]" as the keyword at the start of ScriptResult.

1 Like

When you open a .js file or save a new file as .js how does it know to use JXA syntax and execution? Do you have to set that manually for each file as you are using it?

I do not have .js files associated with JXA. I have .scpt files associated with JXA, which I think is the default, but I might be wrong.

I could never figure out how to get .js files to be associated with JXA. I’m sure there’s a way, and if you figure it out, let me know.

As an aside, because I’m not using .js files for JXA, in order to get linter to work with .scpt files, I have to switch the grammar to JS when I want to use linter. Then I switch it back. I have some KM macros for this.

Atom doesn't really store files in (compiled) .scpt format the way Script Editor does, does it? You're just fooling it, right?

I don’t think it will store it in compiled form. I could be wrong, though, but I don’t think so.

When I need to store a compiled script, I use Script Editor.

The Script package in Atom can read in binary .scpt (extracting source code)

(http://www.uesp.net/wiki/Tes4Mod:Mod_File_Format/SCPT)

but can’t write it.

(It writes out text files with an .scpt extension – Script Editor often seems puzzled by them – reading but declining to resave/rewrite them, and is less puzzled or unprepared if they come back in with an .applescript extension)