/ Komodo

Creating a dynamic toolbar button for Komodo X

What are these "dynamic buttons"? This is a new thing in Komodo IDE X.
Depending on your environment, opened files, etc., these buttons will appear and disappear.
If you're editing a markdown file, the markdown dynamic button will appear in the side toolbar. That's the idea.

A button could do a lot of things. You can run shell commands or do anything else that's provided by Komodo's SDK. I'm going to write a simple button that will show a notification with the path of current project. Simple eh? Though this will teach you:

  1. Writing statements when the button should appear.
  2. How you can access Komodo's SDK.

Let's get started!

Creating an userscript

This step is pretty easy - open the right pane, right click - Add - New Userscript.
Name it somehow and close the popup. Then right click on the userscript - Edit Userscript.

The code!

The first thing we'll do is create a local scope:

(function() {
    // code
})();

With this we can avoid any conflicts with global variables.

Then, require the dynamic-button module:

const db = require('ko/dynamic-button');

Then, require a legacy module that we will use to get an information about current project.

const koPart = Cc["@activestate.com/koPartService;1"].getService(Ci.koIPartService);

We'll use it to check if there's a project opened and then get the project path.
As I said, our button will show a notification. So we need the notification module!

require('notify/categories').register('my_dynamic_button', {
    label: "Dynamic button"
});

We'll register a category for our notifications, so we can use it in the future.

Now, require the module to send notifications:

const notify = require('notify');

We're done with requiring things. Let's get into the logic!

The logic

First, we'll create a function that will return current project path or null.

const project = () => {
    if (koPart.currentProject !== null) { // check if a project is opened
        return koPart.currentProject.liveDirectory;
    } else {
        return null;
    }
};

Then, we register our button:

const button = db.register({
    label: "My button",
    tooltip: "Tooltip for my button",
    icon: "cloud", // a nice cloud
    events: [
        "current_view_changed",
        "current_place_opened",
        "file_saved"
    ], // the list of events that will fire isEnabled function
       // note it's optional, if you don't specify this varialbe the list will be the same
    isEnabled: () => { // our checking function, true enables it, false disables it
        return project() !== null;
    },
    command: () => {
        notify.send(`Button: path: ${project()}`, {
            priority: "info",
            category: "my_dynamic_button"
        });
    }
});

And... done! Now run your userscript. If you don't see a cloud icon in your side toolbar, you didn't open a project then. That means our statement works.

When you click on the button, a notification will appear (probably in the top of your editor, inside Commando thing).

The final code

(function() {
    const db = require('ko/dynamic-button');
    const koPart = Cc["@activestate.com/koPartService;1"].getService(Ci.koIPartService);
    require('notify/categories').register('my_dynamic_button', {
        label: "Dynamic button"
    });
    const notify = require('notify');
    
    const project = () => {
        if (koPart.currentProject !== null) {
            return koPart.currentProject.liveDirectory;
        } else {
            return null;
        }
    };
    
    const button = db.register({
        label: "My button",
        tooltip: "Tooltip for my button",
        icon: "cloud", // a nice cloud
        events: [
            "current_view_changed",
            "current_place_opened",
            "file_saved"
        ], // the list of events that will fire isEnabled function
           // note it's optional, if you don't specify this varialbe the list will be the same
        isEnabled: () => { // our checking function, true enables it, false disables it
            return project() !== null;
        },
        command: () => {
            notify.send(`Button: path: ${project()}`, {
                priority: "info",
                category: "my_dynamic_button"
            });
        }
    });
})();

Post Scriptum

Thanks a lot to Carey Hoffman and Nathan Rijksen from ActiveState for giving me an example code of a dynamic button that I were able to review :)