Customize and Extend Komodo with Userscripts (Slack Edition)

Customize and Extend Komodo with Userscripts (Slack Edition)

kjljlk

Morning (or afternoon) all. Not too long ago I wrote an uncharacteristically
long blog post about the Slack integration I had written for the Komodo 10.2.0 release. As I was writing the blog, and doing a bit of backtracking of the work I had done, I ended up finding the four userscripts I had written that ultimately became the full fledged feature, Slack Sharing in Komodo.

Today I’ll walk through creating one of these userscripts to demonstrate how customizable Komodo is. With userscripts, you can add powerful functionality to Komodo to make it do whatever you need for developing your web apps (in our case, pushing a file snippet to a Slack channel!).

Customize & Extend Komodo

As many of you may know, and many more may not, Komodo is extra-emely
customizable. Between the Addon mechanic, Javascript and Python userscripts, and
the Color Scheme Editor introduced in Komodo 10, Komodo is likely one of the most extensible IDEs available. Obviously I’m
biased…

Throughout this blog there will be snippets of code that you can run for
yourself to see what they do. Just open the JS Console and paste the commands
there: View menu > Tabs & Sidebars > Console.

You can also create a new userscript in your toolbox and follow along there: View menu > Tabs & Sidebars > Toolbox: Gear icon > New Userscript.

You can either edit the userscript in the properties dialog that appears or save and close the dialog then right click the userscript in the toolbox and Edit Userscript which will open it in an editor view. Note: for the Slack code to work, you will have to create an App for your Slack team and return the authentication key provided for API calls. Check out their docs for more information

For the rest of the blog, I’m going to focus on a subset of the above mentioned areas of customization and further, a subset of the code and tools available therein. I’m talking of
course about userscripts and the Komodo CommonJS style SDK.

What I used

For this userscript I used 4 different SDKs, one of which is provided by the
Mozilla code Komodo is built on top of.

The Userscript

I’m going to go over the userscript as if I’m just writing it. I’ll go
section by section then post the whole script at the bottom. As we go you can
use console.log() to output things in the JS console if you want to have a
better understanding of what’s going on. Remember, console.log(object) will
dump the object to the console so you can click through it and see what it is.

Authentication

Instantiate your API key.

token = "xoxp-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXXX-XXXXXXXXXX";

As mention above you will need to get your own API key to run this script. See
https://api.slack.com/ for more information.

Required SDKs

Load our SDKs. As you can see it’s as easy as writing NodeJS.

var ajax = require("ko/ajax"); // To make API calls to Slack
var view = require("ko/views").current().get(); // To get meta information about the file
var editor = require("ko/editor"); // To get information about the contents of the file
var qString = require("sdk/querystring"); // create an query string for our API call

Content to Send

The most logical thing to me was to get either the selection or the entire file
if there was no selection. We also want a file name to identify the code and
the programming language of the file so Slack knows how to style the code when
it posts the snippet to your channel.

var content;
var filename;
if (editor.getSelection.length === 0) {
// If we have nothing selected then get the entire contents of the file
content = view.scimoz.text; // Everything in the file
filename = view.title; // The name of the file including extension
} else {
// otherwise, lets get the selection and indicate in the name that it's
// part of a larger file.
content = editor.getSelection(); // Gives us the selection
var viewTitlesplit = view.title.split("."); // view.title gives us the filename
var name = viewTitlesplit.shift() + "-snippet";
var extension = viewTitlesplit.toString();
filename = [name,extension].join(".");
}
var language = editor.getLanguage() || "text";

Try printing the results of the above with and without a selection in your
open file: console.log("content:"+content+"
Filename: "+filename)

Create the API Call String

Now that we have what we want to send, we can create the query string using
the stringify function of the querystring SDK then append it to the API
method URL.

var params = qString.stringify(
{
token: token, // I hope you have this by now ;)
content: content,
filetype: language,
filename: filename,
channels: "MyChannel", // I hope you know what channel you want cause I can't see the future nor read your mind :P
// but that's a little out of scope here.
});
var baseUrl = "https://slack.com/api/files.upload?"; // https://api.slack.com/methods/files.upload
var request = baseUrl+params; // Append the query string to the URL

Make the API Call

And we’re basically done.

Using the AJAX SDK in Komodo makes this last step a breeze.

ajax.post(request,(code, response) =>
{
var response = JSON.parse(response);
console.log("code: "+code+"
ok: "+response.ok+"
File: "+JSON.stringify(response.file));
});

After a brief delay, that will dump the server code (was the API server able to
handle your query?) and the status from the Slack API (Did the query make sense
to the API code?).

The Final Product

And that’s it! Your userscript should be working and should look like this:

token = "xoxp-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXXX-XXXXXXXXXX";  //Replace this line with your own API key
var ajax = require("ko/ajax"); // To make API calls to Slack
var view = require("ko/views").current().get(); // To get meta information about the file
var editor = require("ko/editor"); // To get information about the contents of the file
var qString = require("sdk/querystring"); // create an query string for our API call
var content;
var filename;
if (editor.getSelection.length === 0) {
// If we have nothing selected then get the entire contents of the file
content = view.scimoz.text; // Everything in the file
filename = view.title; // The name of the file including extension
} else {
// otherwise, lets get the selection and indicate in the name that it's
// part of a larger file.
content = editor.getSelection(); // Gives us the selection
var viewTitlesplit = view.title.split("."); // view.title gives us the filename
var name = viewTitlesplit.shift() + "-snippet";
var extension = viewTitlesplit.toString();
filename = [name,extension].join(".");
}
var language = editor.getLanguage() || "text";
var params = qString.stringify(
{
token: token, // I hope you have this by now ;)
content: content,
filetype: language,
filename: filename,
channels: "MyChannel", // Replace this line with your channel.

// but that's a little out of scope here.
});
var baseUrl = "https://slack.com/api/files.upload?"; // https://api.slack.com/methods/files.upload
var request = baseUrl+params; // Append the query string to the URL



ajax.post(request,(code, response) =>
{
console.log("code: "+code+"
Response: "+response);
});

Troubleshooting

There were a couple places above that you have to enter information specific to
your Slack team and channel. These are the errors you’ll get if you didn’t do
that.

not_authed

code: 200 Response: {"ok":false,"error":"not_authed"}

If you get a response from the API server that looks like the above then you
didn’t get an API key. Again, see the Slack Docs for this information.

invalid_channel

code: 200 Response: {"ok":false,"error":"invalid_channel","channel":"MyChannel"}

This means you didn’t add a real channel to the request we created in the
Create the API Call String section.

Final Words

I say this all the time to people when I’m talking about my job, but I’m insanely lucky to be where I am. Komodo is such a huge beast of a program (if you don’t think it’s huge then we’re doing our job well) that I’m constantly learning new things. This was one of those cases where I got to learn something new and really cool. I’m really glad that I could write this blog and share what I learned with you.

Now take what we’ve covered and make something cool! That’s what Komodo IDE is for! Enjoy!

PS. Licensing

Just a heads up to anyone reading this and sampling the code above: all code in
this blog is licensed under the MIT license
so feel free to use it how you like.

Carey Hoffman

Carey Hoffman

Carey made the logical switch from snowboard instructing and treeplanting to the technology industry in 2009, taking database and network administration at Vancouver BC's BCIT college. Having started out on the technical support and QA team for ActiveState he now works on the Komodo development team as a front and backend software engineer.