Komodo is being retired

It looks like my old go-to editor, Komodo IDE, is being retired. I find this slightly sad, since I was a Komodo Edit and Komodo IDE user for many years.  Of course, it's been several years since I used Komodo, but it still feels like a loss to see something you were once very invested in being put out to pasture.  Although it is good to see that ActiveState chose to open-source Komodo IDE rather than just letting it die, so bravo!

Of course, when you read the rationale, you can't really disagree.  The number of free, high-quality editors and IDEs makes "generic code editor" not exactly the best business to be in.  Especially when you're tied to an archaic, end-of-life framework like XUL.  And given that they don't exactly have a large team working on Komodo (never more than 4 people, according to the article), rewriting sounds like it would be a pretty huge effort.

Looking at my blog history and tag list, it seems I started using Komodo Edit some time before November of 2008, used that for several years, and then upgraded to Komodo IDE.  I posted about looking for a new IDE in March 2017.  So I was a Komodo user for 8+ years.  Not  bad run.  It was a good IDE for a long time.  Sadly, I was one of those people who didn't like the UI revamp that came out in version 10.

However, I was somewhat lucky in my timing, because by the time I dropped Komodo, Visual Studio Code had come out.  So I was starting to use Vim seriously in the era where language servers were becoming a thing.  The importance of the Language Server Protocol (LSP) for making "Vim as IDE" viable cannot be understated.  This makes things way easier and better.  All you need is a Vim plugin that speaks LSP (I use coc.nvim), and you can get all the same code intelligence that VS Code does.  That means you can get all of the goodness of Vim without having to sacrifice your intellisense.  It's a good time to be coding.

Vim emulation in Komodo

Authors note: Here's yet another installment of "From the Archives".  Clearly I haven't really felt like coming up with new ideas lately.  I blame the pandemic.  Seriously - I'm not going to be back in the office until at least next summer.  Even though restrictions have eased (at least for the time being), lock-down fatigue has definitely long since set in.

At any rate, this is another one on using Komodo with Vim emulation.  This was written on April 16, 2014, just a few days after the last one on the same topic.  These days I'm using Vim all the time, so none of this is relevant to me anymore.  However, it is a nice example of how it's possible to extend a good IDE to customize your workflow.

In this case Komodo is (or was) customizable using JavaScript, which is nice - lots of people know JavaScript.  The down side is that, to do actually useful thing, you also it also used XUL and SciMoz, the Mozilla Scintilla binding.  These are less commonly known, to put it mildly.

To be fair, Vim isn't much better on this score.  While it supports multiple scripting languages, the primary one is, of course, VimScript, which is...not a great language.  However, it's also quite old, quite well documented, and there are lots of examples of how to use it.  The VimScript API is also pretty stable, as opposed to Komodo, which was in the process of moving away from the XUL-based stuff when I stopped using it.  And really, a little VimScript will actually take you farther than you think.

In any event, I guess the idea is that it's good to know how to customize your editor, at least a little.  You know, sharpening the saw, knowing your tools, and all that.  Good stuff.  Enjoy!


Since upgrading to Komodo IDE, I've been looking a little more at customizing my development environment.  This is actually made somewhat easier by Komodo's "sync" feature, which will synchronize things like color schemes, key bindings, etc. between IDE instances via ActiveState's cloud.

Anyway, as part of this I've also been looking more at the Vim keybindings.  I've been a casual Vim user for a very long time, but I was never hard-core enough to do things like stop using the arrow keys or give up using ctrl+C and ctrl+V for copy and paste.  So now I'm trying to do just that.

Of course, Komodo's VI emulation mode is a pale imitation of what's available in Vim.  However, even that pale imitation is actually pretty good.  In fact, its even better than Komodo's documentation would lead you to believe.  In addition to the basic modal editing stuff, Komodo supports a decent range of movement commands, variants of change and delete commands, etc.  Basically, it supports everything I already knew about plus a lot more.  So now I'm trying to get that extra stuff into my muscle memory.

In the course of looking at some Vim command guides, I naturally came across some handy looking commands that Komodo didn't support.  So I'm going to try to fix that.

The first one is the reg command.  Vim's registers were something I hadn't really worked with before, but it turns out that they're not only pretty cool, but that Komodo actually has some support for them.  I only know this because the documentation mentions the key binding for the "set register" command.  However, it doesn't implement the reg command, so you can't actually see what's in any of those registers.

So, long story short, I fixed that with a macro.  Just create a new macro named "reg" in your "Vi Commands" folder in your toolbox and add the following code (this requires another macro, executed at start-up, containing the "append_to_command_output_window" function lifted from here):

var viCommandDetails = Components.classes['@activestate.com/koViCommandDetail;1'].
                                getService(Components.interfaces.koIViCommandDetail);
var count = new Object();
var args = viCommandDetails.getArguments(count);

append_to_command_output_window('');
append_to_command_output_window("--- Registers ---");

for (item in gVimController._registers) {
    if (args.length > 0 && args.indexOf(item) < 0) {
        continue;
    }
    if (typeof gVimController._registers[item] !== 'undefined') {
        append_to_command_output_window('"' + item + '   ' + gVimController._registers[item].trimRight());
    }
}

This allows you to type ":reg" and get a list of the current registers in the "command output" window in the bottom pane.

Another good one:

var scimoz = ko.views.manager.currentView.scimoz;
if (scimoz.selText.length == 0) {
    ko.commands.doCommand('cmd_vim_cancel');
} else {
    ko.commands.doCommand('cmd_copy');
}

This can be bound to ctrl+C and allow you to keep the default "copy text" behavior when there is text selected, and still work for Vim's "back to normal mode" when nothing is selected.

Komodo and Vim

Author's Note: We're back with another installment of "From the Archives", the blog show where I declare writing bankruptcy and just post an old, half-finished article that's been sitting in my drafts for years.  This entry is from April 9, 2014.  This was in the midst of my long stint as a Komodo IDE user. 

One of my favorite things about Komodo was that it had pretty good Vim emulation.  I started using that because a few years before I'd spent a lot of time going back and forth between a Windows PC and a Macbook Pro.  The Macbook keyboard had that weird Apple layout going and it routinely messed with me, so I eventually gave up and decided to use Vim-mode because that's the same on both platforms.

Of course, things have changed since then.  I've become a full-time Vim user, and have all the fancy faux-IDE stuff set up.  I actually like it so much that I stopped using PHPStorm for work and switched to doing all my development in Vim.  So this post is no longer relevant to me, but it at least has a few handy links, so enjoy!


I've been a Vim user more or less since I started using Linux.  Mind you, I was never really a hard core Vim user.  I still use the arrow keys, for instance, and manage to get by on maybe a couple dozen keybindings and commands.  I have no clue how Vim's scripting or configuration systems work.  All I know about ctags is that they're a thing that exists.  So really, I'm more of a dabbler.

The other part of this is that I like at least a small amount of IDE in my normal working-day editor.  I kind of like having some sort of "project view" of my files, a code hierarchy viewer, some form of Intellisense, etc.  And while you can get most of the stuff I like in Vim, they're not there out of the box.  And even if you can get them, you can't count on having an obvious graphical way to manipulate them.  Typically, you just have to read the documentation to find out what the key bindings are to trigger everything.

So the upshot of this is that I use Komodo IDE with the Vi emulation setting.  This essentially turns on a Vim emulation mode that makes the editor modal and enables a lot of the standard Vim keybindings as well as a small subset of common commands.  So I get Vim goodness with all the convenience of a full IDE.  I had never really looked closely at just how much of Vim Komodo would emulate, though - I just knew it supported everything I commonly used.

Well, I had some extra time after finishing all my bug fixes the other day, and since really learning Vim has been on my list of things to do for, er, over 10 years, I decided to look up some Vim reference sheets and see how many of the commands and keybindings actually worked in Komodo.  Turns out it was a pretty decent amount.  (Note from the future: I didn't write down the details at the time and don't care enough to catalog now that I no longer use Komodo.  Suffice it do say that Komodo's Vi emulation was actually pretty good.  Maybe not as good as IdeaVim, but pretty good.)

Looking for a new editor

A couple of weeks ago I started looking into new code editors.  I've been using Komodo for eight or nine years now, counting both KomodoIDE and KomodoEdit, but I'm growing dissatisfied with it.  In fact, I'm becoming unsatisfied enough that I think the time has come to move on.  However, I'm not sure I see an obvious candidate for a replacement.  So in this post, I'll talk about some of the things I find lacking in Komodo and what I'm looking for in an editor.

Why the change?

Let me start by saying that I'm not trying to bad-mouth Komodo here.  I have used it for a long time and it has served me well.  The people at ActiveState are nice and they do good work.  But the direction it seems to be heading in doesn't mesh well with my needs and I'm not sure the cost/benefit analysis of sticking with Komodo makes sense anymore.  Maybe this can provide some insight to the Komodo development team that can help them improve the IDE.

My dissatisfaction started a few months ago, when my team transitioned to a different product.  Unlike the last product we worked on, this one doesn't belong to just us.  This one is core to the company's business, and has several other development teams working on it, not to mention all the other groups that come in contact with it.  As such, there's an existing process and structure that we needed to adhere to, and it quickly became apparent that adhering to that was much easier if you were running the standard development setup, which is PHPStorm on Ubuntu.  I was running KomodoIDE on Windows, so this was a problem.  I was able to use WSL to get around the Linux part, but KomodoIDE just didn't offer the same features that I needed from PHPStorm.

So let's use that as a starting point.  What does PHPStorm offer that Komodo can't compete with at present?  Well, for purposes of the product I'm working on, here's the list:

  1. Code intelligence.  This is by far the biggest factor.  I'm not just talking about intellisense here.  I mean finding and navigating the actual places in the code where a class, function, or method is used or defined.  And not just text search, but actually knowing about the class and its inheritance hierarchy.  PHPStorm is actually pretty awesome at that.  Komodo's code intel., at least least for PHP and JavaScript, is buggy at best and totally broken at worst.  The quality of the experience also seems to vary hugely depending on the codebase you're working with.  It's nice that they have something for code intel., but you can't really rely on it.
  2. Validations.  PHPStorm integrates with phpcs, which is nice because we need to actually adhere to PSR-2.  Komodo doesn't have that built in.  This might seem like a trivial thing because, after all, I can always just run phpcs from the command line.  However, having the check done in the editor is actually hugely useful, because we have a lot of legacy code that doesn't adhere to PSR-2, which makes selectively running the checks for only the code you changed awkward.  Seeing violations in your editor gives you a nice, simple way to catch mistakes you made before they get to code review.
  3. Symfony support.  While it's not built in, PHPStorm has a pretty good quality plugin for Symfony support.  We use Symfony, so this is really nice.  Komodo doesn't have that.

Those things are important, but they are specific to the new product I'm working on.  If these were my only complaints, I would happily continue using Komodo for the foreseeable future and just use PHPStorm for that one project at work.  But they're not.  The list of annoyances and things I don't like has been slowly growing over the years.  This includes actual problems and bugs, missing functionality, and road-map issues (i.e. disagreement with the direction I see Komodo going).  Here's a summary:

  1. Kinda buggy.  I hate to say it, but I've seen a decent amount of weird errors, crashes, and just plain strange behavior in Komodo.  Not a huge number - it certainly hasn't been buggy enough to get switch editors - but it's still a non-trivial issue.  I'll give just a few examples here to give you the flavor of my complaints.
    1. Maybe it's just my perception, but it's rare for the error log or console to not have something in it.
    2. Sometimes when I'm doing things in the "places" panel, some keypress will trigger a change to the next pane of that panel.  I'm not sure what it is and I can't seem to do it on purpose.
    3. I'm constantly empty getting "find" panes accumulating in my bottom panel.  Again, I'm not 100% sure what causes them and can't seem to reproduce intentionally.
    4. I've tried numerous times on numerous versions of Komodo to set up the keybindings for "focus X pane", but they just don't seem to work at all.
    5. There are various places in the settings UI where one setting determines another, but it's not clearly indicated.  So you can change a setting, click OK, and your change will just be ignored because it's invalid, but there's no indication of that.  A good example is the new unit test runner.  For options other than "custom", the testing framework determines which parser is used, but you can still change the parser in the UI.  It just doesn't do anything.
    6. The syntax checking preferences for JavaScript allow you to set a custom JSHint version to use, probably because the integrated one is kind of old.  I've tried this numerous times and have never been able to get it to work.  Oh, and speaking of JSHint, I'm still kinda miffed that Komodo 10 removed the graphical JSHint configuration UI.  Now there's just a text area to enter your settings, so you have to go to the JSHint site and look up the options rather than just being able to pick from a list.
  2. Pretty over functional.  In the last few releases, some of the tools have been revamped in such a way that makes them prettier, but in my opinion doesn't actually make them more useful.  The two big examples that spring to mind are version control and unit testing.
    1. In older versions of Komodo, my only complaint about the VCS integration was that there wasn't an easy way to do a commit of all pending changes in the project - I fixed that myself with a simple macro.  In the new version, they fixed that problem.  But at the same time, the VCS widget no longer displays changes for added files, which is a big pain.  I typically use my VCS diff for pre-commit code review, so it's kind of inconvenient to have to switch to another view to do that.
    2. The new unit test runner in Komodo 10.2 looks very pretty.  However, they removed the key bindings I was using to run the current test suite.  And it didn't detect my old test suites, so I had to recreate them.  They also changed the name-humanizing algorithm, so that test names that used to be rendered nicely in the runner aren't anymore.
  3. Features I don't care about.  It feels like there have been a few of these added lately.  Some of them seem like things that are really just gimmicks that look good in marketing material but don't provide any value.  Others do provide genuine value, but seem tacked on to pad the feature set, i.e. they're useful, but I don't see the point of having them right in the IDE.  Some examples include:
    1. Collaboration.  You can do real-time editor sharing with someone else using KomodoIDE.  Cool!  And maybe it would be useful if I was doing remote pair programming with someone else who uses Komodo.  But I'm not, so I've never actually used it.  I suppose this could substitute for some of those "social coding" web editors, but this doesn't feel like a general enough use-case to want it integrated into my IDE.
    2. Sharing to kopy.io.  Upload code snippets directly to a code-sharing website.  Nice!  But again, that's something that's not hard to do without IDE support and that I seldom or never do it anyway.  And even if I did, I'd just create  gist on GitHub, not use a new site.
    3. Slack sharing.  You can share code in a Slack channel right from inside Komodo.  Great!  But again, I don't do this often and it's not clear how this is easier than just copy-and-pasting the code into Slack.
    4. Minimap.  A 10,000-foot overview of how your code looks that replaces the traditional scroll bar.  I think Sublime Text had this first.  Sure, it looks really cool, but does anyone actually use these things?  I don't spend a lot of time looking for code segments based on the shape of the text, so it's never been clear to me what useful information this provides.
    5. HTTP inspector.  This is actually an older feature - an HTTP proxy that allows you to inspect traffic.  And it's a genuinely valuable thing for a developer to have.  But you still have to set it up like any other HTTP proxy, so it's not clear how having this baked into the IDE is better than just using a stand-alone proxy app.  And again, this isn't something I need on a regular basis so I've never used it for actual work.
  4. Features that are strange or hard to use.  There are also features that I use, or would like to use, that either don't make sense or don't quite do what I need.  In other words, they could be really good and useful, but they fall short.  For instance:
    1. Keyboard navigation.  Komodo actually has a pretty nice configuration interface for setting up keyboard shortcuts.  Unfortunately, a lot of the actual bindings you might want don't exist (or don't work, as previously noted).  But my big gripe is that navigating around the UI using the keyboard is difficult, particularly in the side/bottom panels.  Trying to navigate between fields within a pane often either doesn't work, gets stuck, switches you to the main editor, or otherwise fails in strange ways.  And as I mentioned earlier, trying to use the keyboard to navigate between different panes seems to just generally not work.
    2. Regex toolkit.  This seems like a really useful tool.  But I'll be darned if I can figure out how it's supposed to work.  Every now and then I try it and I always spend more time trying to figure out how it works than it would take so just write a one-off test script to test the regex.
    3. Publishing.  Komodo has a publishing tool that lets you push your code up to a remote system for testing.  That's a very nice and useful thing.  Except that it's actually a "synchronizer," by which I mean it only does two-way synchronization of files with a remote server.  Why?  What if I don't care what's on the server and just want to clobber it every time?  That's not such an uncommon occurrence with test servers.  In fact, for me, wanting to pull in changes from the remote servers is distinctly an edge-case, not something I'd want to happen by default.

I could probably go on, but I think I've made my point.  It's not that Komodo is a bad IDE - far from it.  But there are a number of rough edges and niggling little issues that are increasingly starting to bother me.  Choice of editor can be a very personal and subjective thing, and for me it just feels like it's time for a change.

What do I want?

So that leaves the question: what do I want in an editor or IDE?  Well, I'm not completely sure.  I've been using Komodo for a long time, and I do like a lot of things about it.  So let's start with a list of some of those things.  That should at least work as a jumping off point.

  1. Good VI emulation.  I've been using VI emulation in my editors ever since I worked for deviantART.  I got a MacBook Pro when I started there and I found the weird keyboard layout completely infuriating, particularly when I switched back to my regular PC keyboard so I decided to just switch to VI key bindings since they're always the same.  Since then, I've gotten progressively more friendly with VI mode, to the point where coding without it feels strange.  Komodo includes fairly decent VI emulation out of the box, and it's relatively easy to add customizations, so any editor I pick up will need comparable VI emulation support.
  2. Code formatters.  One of the really handy features of Komodo is built-in code formatters.  My most common use-case for this is copying some JSON out of the bowser network monitor, pasting it into Komodo, and formatting it so I can analyze it.  It would be really nice for a new editor to support something like that.
  3. Light-weight.  A concept of "projects" is nice in an IDE, but sometimes I just want to quickly open a file.  So I'd rather not use an IDE that takes ages to start up and insists that everything be part of a project (I'm looking at you, Eclipse).  Komodo is pretty good in that regard - it can just start up and open a file without it being too much of an ordeal.
  4. Extensibility.  No editor or IDE is ever perfect out of the box, so it's important to have a decent extension ecosystem around your editor.  Komodo is pretty good in this regard, with a community site offering a nice assortment of extensions.
  5. Scriptability.  In addition to extensions, one of the things Komodo gets really right is giving you the ability to easily write simple scripts to automate things.  It lets you write user scripts in JavaScript that can be fairly easily hooked into the UI.  This is huge.  There are a lot of "small wins" you can achieve with this kind of scripting that will really improve your workflow.  Supporting extensions is great, but it's hard to justify integrating a feature into your IDE if you need, e.g., an entire Java build environment to write an extension for something you could do in five lines of shell.
  6. Multi-language.  This is a big one.  If you regularly code in more than one language, having to learn a different IDE for each one is a real drag.  In the best-case scenario, you have to configure the same things for each editor.  In the worst-case scenario, you have to learn two completely different tools with completely different features.  Most of my professional work is in PHP and JavaScript these days, but I also do some Python, SQL, BASH and PowerShell scripting, and I'm trying to learn Haskell.  So given the choice, I'd rather learn one editor inside and out than have a bunch of language-specific editors that I use as "notepad with some extra features".
  7. Cross-platform.  Right now I use Windows both at home and at work, but that's not set in stone.  I actually use Windows at work by choice (yeah, yeah, I know) - there are a few people with MacBooks, but most of the other developers use Ubuntu.  In the past, I've gone back and forth between platforms, so running on Windows, Linux, and MacOS is a hard requirement for me.  I don't want to be tied to one platform or have to learn a different IDE for each if I decide to switch.
  8. The right feel.  This one is highly subjective, but it's important to me that my IDE feel smooth to use.  I want it to work with me, rather than feeling like I have to adapt to it.  This has always been my problem with Eclipse - I feel like the UI doesn't really adapt smoothly to what I want.  Something about coding in it just feels a little "off" to me.

 Time to experiment

So it's time to start doing some experimentation.  It took me a long time to finally settle on Komodo, so I'll probably go back and forth a few times.  

I've got lots of choices, to be sure.  Back when I settled on Komodo Edit, I was looking primarily at free and open-source editors.  My use of Komodo IDE grew out of that.  These days, I'm not as price-sensitive, so commercial IDEs are definitely on the table, provided they have reasonable non-Enterprise pricing (i.e. I'm not gonna spend $2000 on one).

Last time I was IDE shopping I looked at a bunch of Linux-only editors, but those are out.  I used Eclipse for a while, but I'm not inclined to revisit that.  I also used jEdit for a while, and while it was fairly nice, it doesn't appear to be getting much active development these days, and I'm not sure it fits my current requirements anyway.  But now we have things like Sublime Text, Atom, Visual Studio Code and the entire suite of Jet Brains IDEs.  So I've got lots of things to look at.  If nothing else, the process will be good for a few blog posts.

Line counting in Komodo

So as part of my ongoing professional improvement program, I've been working my way through PSP: A Self-Improvement Process for Software Engineers.  And by "working", I mean I'm doing the exercises from the SEI website and everything.  So far it's actually quite an interesting process - I'd definitely recommend it to any professional software developer, even if you're not interested in using the process, just as "food for thought".  You can pick up a relatively cheap used copy of the book on Amazon (it is technically a textbook, so new ones are a little pricey).  I'll have to write a post on it when I'm finished.

Anyway, the PSP uses line-of-code counting to estimate program size, defect densities, etc.  So I thought it would be nice to be able to run line count reports right from within Komodo.  Fortunately, it turned out to be pretty easy.  I just lifted some code from Nathan Rijksen's "Open Terminal Here" macro as a starting point and went from there.  The macro just takes the selected files or directories in you "places" pane and appends them to a custom command.  I've used cloc as my line-counting tool of choice for a number of years, but you can change the command to be whatever you want (even "wc -l" if you really want).  I also added in a little code to calculate and run from a common base directory, so that you wouldn't get a full, absolute path for every item in the report.  The command output is sent to the Komodo output pane.

The code for the macro is below.  Or, if you're feeling lazy, you can just download the tool here and drop it in your toolbox.

/**
 * Adds a "Count LOC" menu item to items in the Places widget.
 * This will run a line-counter on the selected paths and display the command output.
 * Based on the "Open Terminal Here" macro by Nathan Rijksen.
 *
 * Usage: Update the "command" variable to contain whatever command you want to run.  The paths to the files selected
 * in the places pane will be appended to this command.
 *
 * If the "use_common_directory" variable is true, then the macro will calculate the deepest common directory of all
 * the selected files and will run the command from that directory, passing relative paths.  For example, if you
 * select files /foo/bar/baz/buzz.js and /foo/bar/fizz/fuzz.css, the command will be run from /foo/bar and will be
 * passed the paths baz/buzz.js and fizz/fuzz.css.
 * If this variable is set to false, then the command will be passed the full, absolute paths to all files and no
 * working directory will be specified for it.
 *
 * @author Peter Geer
 * @contributor Nathan Rijksen
 * @contributor Mathieu Strauch
 * @version 0.1
 */
/*global ko, extensions:true */

// Register namespace
if ((typeof extensions) == 'undefined') {
    extensions = {};
}
extensions.CountLOC = {};

(function() {
    
    var command = "cloc --by-file --force-lang=PHP,phtml",
        use_common_directory = true,
        label = 'Count LOC',
        id = 'contextCountLOC',
        sibling,
        d,
        mi,
        callback,
        longest_common_path;
    
    longest_common_path = function(list) {
        var longest_item = list[0].substr(0, list[0].lastIndexOf('/')),
            i = 0;
        for (i = 0; i < list.length; i++) {
            while (longest_item !== '' && list[i].indexOf(longest_item) < 0) {
                longest_item = longest_item.substr(0, longest_item.lastIndexOf('/'));
            }
            if (longest_item === '') {
                break;
            }
        }
        return longest_item;
    };
    
    callback = function(e) {
        var i = 0,
            cmd = command,
            curr_dir = null,
            uris = ko.places.viewMgr.getSelectedURIs();
        
        if (uris.length === 0) {
            return;
        }
        
        // Clean up the URIs.
        for (i = 0; i < uris.length; i++) {
            uris[i] = uris[i].replace(/^[a-zA-Z]+:\/\//,'');
            if (uris[i].match(/^\/[a-zA-Z]:\//)) {
                uris[i] = uris[i].substr(1);
            }
        }
        
        // If set, turn the absolute paths into relative paths.
        if (use_common_directory) {
            curr_dir = longest_common_path(uris);
            if (curr_dir !== '') {
                for (i = 0; i < uris.length; i++) {
                    uris[i] = uris[i].substr(curr_dir.length + 1);
                }
            } else {
                curr_dir = null;
            }
        }

        // Prepare command for each platform
        for (i = 0; i < uris.length; i++) {
            cmd += ' ' + uris[i];
        }

        // Run command, show output in bottom pane
        ko.run.command(cmd, {cwd: curr_dir, runIn: 'command-output-window'});
    };
    
    // Get places pane document object
    d = document.getElementById('placesViewbox').contentDocument,

    // Remove existing menu entry if it exists
    mi = d.getElementById(id);
    if (mi) {
        mi.parentNode.removeChild(mi);
    }

    // Get the sibling element which we want to insert our menu item after
    sibling = d.getElementById('placesContextMenu_rename');
    
    // Create our menu item
    mi = document.createElement("menuitem");
    mi.setAttribute("id", id);
    mi.setAttribute("label", label);

    // Add event listener for when the menu item is used
    mi.addEventListener('command', callback);

    // Append menu item to popupmenu
    if (sibling && sibling.parentNode) {
        sibling.parentNode.insertBefore(mi, sibling);
    }

}.apply(extensions.CountLOC));

Swag shipment

My shipment of Komodo IDE swag arrived today.  I won a Twitter contest to find an Easter Egg in the new Commando feature of Komodo 9.  Turns out that if you type "kitt" or "michael" into the Commando box, it will play an animation of Kitt's cylon eye-light, complete with whooshing sound, from Knight Rider.

So my prize was a Komodo IDE T-shirt, some Komodo and Stackato stickers, and a pack of Komodo IDE playing cards. The shirt is actually pretty nice.  It just has the komodoide.com URL on the back and that logo on the front.  A nice little swag selection, at any rate.  Thanks, ActiveState!

Reference project root in command

Continuing on the Komodo macro theme for this week, here's another little macro template that might come in handy.  This one is just a quick out outline for how to reference your project's root directory when running a command.

As you may know, Komodo's commands support a variety of interpolation variables to do things like insert file paths and other input into your commands.  The problem is that there's no variable to get the base directory of your current project - by which I mean the "project base directory" that you can set in your project properties.  Oh, sure, there's the %p and %P variables that work on the current project, but they don't get the project base path.  They get the path to the project file and the directory in which the project file is contained.  That's fine when your project file lives in the root of your source tree, but if you want to put your project files in another location, it doesn't help.

Sadly, there is currently no way to get this path using the interpolation variables.  However, it's pretty easy to get with a macro.  The only problem with that is that the macro syntax is a little odd and the documentation is somewhat lacking.  The documentation for ko.run.runCommand() does little more that give the function signature, which is bad because there are 17 parameters to that function, and it's not entirely clear which are required and what the valid values are.  Luckily, when you create a command, the data is stored in JSON format with keys that more or less match the parameter names to runCommand(), so you can pretty much figure it out by creating the command as you'd like it and then opening the command file up in an editor tab to examine the JSON.

Anyway, here's macro template.  Needless to say, you can substitute in the project base directory at the appropriate place for your needs.  In my case, I needed it in the working directory.

var partSvc = Cc["@activestate.com/koPartService;1"].getService(Ci.koIPartService),
    baseDir = partSvc.currentProject.liveDirectory,
    dir = baseDir + '\\path\\to\\OpenLayers\\build',
    cmd = 'python build.py';
ko.run.runCommand(window, cmd, dir, undefined, false, false, true, "command-output-window");

Better project commit macro

Several months ago, I posted a Komodo IDE macro to run a source control commit on the current project.  That was nice, but there was an issue with it: it only sort of worked. 

Basically, in some cases the SCC type of the project directory was never set.  In particular, if you focused on another window and then double-clicked the macro to invoke it, without touching anything else in Komodo, it wouldn't work.  While this scenario sounds like an edge-case, it turns out to be infuriatingly common, especially when you use multiple monitors.  The obvious example is:

  1. Make some changes to your web app in Komodo.
  2. Switch focus to a browser window and test them out.
  3. See that everything works correctly.
  4. Double click the commit macro to commit the changes.
  5. Wait a while and then curse when the commit window never comes up.

I'm no Komodo expert, so I'm not sure exactly what the problem was.  What I did eventually figure out, though, is that Komodo's SCC API doesn't seem to like dealing with directories.  It prefers to deal with files.  And it turns out that, if you're only dealing with a single file, the "commit" window code will search that file's directory for other SCC items to work with.

So here's an improved version of the same macro.  This time, it grabs the project root and looks for a regular file in it that's under source control.  It then proceedes in the same way as the old one, except that it's much more reliable.

(function() {
    "use strict";
    
    // Find a file in the project root and use it to get the SCC type.  If we
    // don't find any files, just try it on the directory itself.
    // TODO: Maybe do a recusive search in case the top-level has no files.
    function getSccType(url, path) {
        var os = Components.classes["@activestate.com/koOs;1"]
                           .getService(Components.interfaces.koIOs),
            ospath = Components.classes["@activestate.com/koOsPath;1"]
                               .getService(Components.interfaces.koIOsPath),
            fileSvc = Components.classes["@activestate.com/koFileService;1"]
                                .getService(Components.interfaces.koIFileService),
            files = os.listdir(path, {}),
            kofile = null;
        // First look for a file, because that always seems to work
        for (var i = 0; i < files.length; i++) {
            var furi = url + '/' + files[i],
                fpath = ospath.join(path, files[i]);
            if (ospath.isfile(fpath)) {
                kofile = fileSvc.getFileFromURI(furi);
                if (kofile.sccDirType) {
                    return kofile.sccDirType;
                }
            }
        }
        // If we didn't find a file, just try the directory.  However, this
        // sometimes fails for no discernable reason.
        kofile = fileSvc.getFileFromURI(url);
        return kofile.sccDirType;
    }
    
    var curr_project_url =  ko.projects.manager.getCurrentProject().importDirectoryURI,
        curr_project_path = ko.projects.manager.getCurrentProject().importDirectoryLocalPath,
        count = 0;
    
    // HACK: For some reason, the SCC type on directories doesn't populate.
    // immediately.  I don't know why.  However, it seems to work properly on
    // files, which is good enough.
    var runner = function() {
        var scc_type = getSccType(curr_project_url, curr_project_path),
            cid = "@activestate.com/koSCC?type=" + scc_type + ";1",
            fileSvc = Components.classes["@activestate.com/koFileService;1"]
                                .getService(Components.interfaces.koIFileService),
            kodir = fileSvc.getFileFromURI(curr_project_url),
            sccSvc = null;
            
        if (scc_type) {
            // Get the koISCC service object
            sccSvc = Components.classes[cid].getService(Components.interfaces.koISCC);
            
            if (!sccSvc || !sccSvc.isFunctional) {
                alert("Didn't get back a functional SCC service. :( ");
            } else {
                ko.scc.Commit(sccSvc, [curr_project_url]);
            }
        
        } else if (count < 50) { // Just in case this never actually works....
            count += 1;
            setTimeout(runner, 100);
        } else {
            alert('Project directory never got a valid SCC type.');
        }
    };
    
    runner();
}());

Quickie TDD with Jasmine and Komodo

I'm currently on my annual "this time I'm really going to start doing test-driven development (or at least something close to it)" kick.  And it seems to be going pretty well, so hopefully this time it will actually stick. 

As I said, I do this every year and testing usually ends up falling by the wayside.  Granted, this is partly just due to a lack of discipline and commitment on my part.  Getting started with a new practice takes effort, and sometimes it's hard to justify that effort when "I've been doing just fine without it for years."  But there's also the matter of the type of projects I work on.  Most of the projects I've worked on have not had an establish test suite or a culture of testing.  Whether it's a work-related project or an old personal project for before I heard the gospel of TDD, the norm has been a sizable, years-old code-base that has few if any tests and isn't really designed to be testable in the first place. 

Getting into TDD with a project like that can be daunting.  Picture PHP code littered with static method calls, system calls, and direct class instantiations at multiple levels.  "You need to inject a mock object?  Yeah, good luck with that."  The classes may be well-defined, but there's not much compartmentalization of responsibilities within them, so inserting test doubles is not always straight-forward.  That leaves you in the unenviable position of either having to rewrite a bunch of existing code to make it unit-testable or set up some real test data and turn the unit test into an integration test.  The first option is obviously preferable, but can be much more risky, especially since you don't already have tests to validate the behavior of the code you need to change.  And while the second approach is certainly better than no tests at all, integration tests are slow to run, cumbersome to set up, and much more prone to breakage when things change.  Faced with a mess like that, it doesn't seem that unreasonable to say, "You know what?  I've got things I need to get done.  I'll get back to those tests later."  But, of course, you never actually do.

This time, I'm doing things a little differently.  For starters, I'm not writing new tests for old code.  I'm just doing the new code.  I'll get to the old code when/if I get around to refactoring it.  That means that I don't have to worry about untestable code, which makes the entire enterprise about a thousand times simpler.  I'm also not working with PHP code for the time being.  I'm trying to do TDD on two projects — one for work that's in JavaScript and a personal one in Python.  For Python, I'm using unittest and mock which, so far, I'm finding to be less of a pain in the neck than PHPUnit.

For the JavaScript project, I'm using Jasmine, which brings me to the title of this post.  Since I'm trying to do TDD (or rather BDD), I quickly tired of alt+TABbing to a browser window and then hitting ctrl+R to reload the page with the test runner.  Sure, it's not a big deal, but it's just one more thing that gets in the way.  I wanted to do what I could do in Python and PHP, which is just hit a hotkey and have Komodo run the test suite right in the same window. 

Turns out, that was actually pretty easy to set up.  I just banged out a quick macro that opens up the Jasmine test runner HTML file in a browser tab or refreshes it if it's already opened.  I bound that to a hotkey and I'm good to go.  Sure, it doesn't use the Komodo IDE testing framework, but that's not the end of the world — I just move it to a split pane and it works out pretty well.  I even added some CSS to the spec runner to make it match my Komodo color scheme.

Here's a screenshot of the side-by-side runner and some (unrelated but public) code:

And here's the macro itself:
(function() {
    var uri = 'file:///path/to/test_runner.html',
        view = ko.views.manager.getViewForURI(uri);
    if (view === null) {
        ko.open.URI(uri, 'browser');
    } else if (view.reload) {
        view.reload();
    } else {
        view.viewPreview();
    }
})();

VI makes so much more sense now

Thanks to this answer from StackOverflow, the key mappings in VI and Vim make soooo much more sense now.  It's all explained by this keyboard layout:

The keyboard layout that was used when VI was created.

The more I use Vim, or the Vim emulation in Komodo, the less sense it makes to use the "escape" key to switch out of insert mode.  I mean, you have to move your hand way away from the home row just to reach it, which is exactly the opposite of how things are supposed to work.  But if you're using this keyboard, then it seems like a completely obvious choice.

Incidentally, after far too many years of suffering with the escape key, I've switched to using the other choices for getting out of insert mode — Ctrl-C and Ctrl-[.  Both do the same thing as the escape key, but require significantly less hand movement and so are faster to type.  Especially Ctrl-C, as most of us are used to using that for copying text to the clipboard.

Incidentally, since I'm using the Vim emulation for Komodo IDE/Edit, I should probably mention that it does support Ctrl-[ out of the box, but not Ctrl-C — that is, naturally, reserved for the "copy" operation.  However, it's easy to change that.  Simply create a new macro with the following code and set the key binding for it to Ctrl-C (you may have to unbind the standard "copy" operation first):

var scimoz = ko.views.manager.currentView.scimoz;
if (scimoz && scimoz.selText.length == 0) {
    ko.commands.doCommand('cmd_vim_cancel');
} else {
    ko.commands.doCommand('cmd_copy');
}

This macro preserves the standard copy behavior by checking if you have any text selected when it executes.  If you do, it does a standard "copy to clipboard".  If you don't, it switches the editor from "insert" mode to "normal" mode.

Project commit in Komodo IDE

Edit (2014-10-09): An improved version of this macro can be found in this post.

So I finally got around to writing a little macro for Komodo IDE that I've been missing for a while.  It has a very simple task - perform a "source control commit" operation on the currently project.  You'd think this would be built in, and it wort of is, but it doesn't work very well. 

In Komodo IDE, the SCC commit action is tied to files and directories.  So if you want to commit an entire directory, you need to select it in the "places" pane (i.e. the file system browser).  And if you want to commit the directory that's currently set as the root of the file view, you either have to go up a level and select it or right-click on an empty spot in the file browser.  So, in other words, it's grossly inconvenient.

Hence this little macro.  Just create a new macro in your toolbox and paste this code into it (note that this doesn't work in Komodo Edit).  Note that this is a little hacky, as some of the SCC initialization seems to be asynchronous and I don't know what (if any) events are fired on completion.  But hey, it works, so close enough.

(function() {
    var curr_project_url =  ko.projects.manager.getCurrentProject().importDirectoryURI,
        fileSvc = Components.classes["@activestate.com/koFileService;1"]
                            .getService(Components.interfaces.koIFileService),
        kodir = fileSvc.getFileFromURI(curr_project_url),
        count = 0;
    
    // HACK: For some reason, the SCC type takes some time to populate.
    // I don't know if there's any event for this, so instead just try it again
    // if it's empty.
    var runner = function() {
        var cid = '',
            sccSvc = undefined;
            
        if (kodir.sccDirType) {
            cid = "@activestate.com/koSCC?type=" + kodir.sccDirType + ";1";
            sccSvc = Components.classes[cid].getService(Components.interfaces.koISCC);
            
            // Get the koISCC service object
            if (!sccSvc || !sccSvc.isFunctional) {
                alert("Didn't get back a functional SCC service. :(");
            } else {
                ko.scc.Commit(sccSvc, [curr_project_url]);
            }
        } else if (count < 10) { // Just in case this never actually works....
            count += 1;
            setTimeout(runner, 100);
        }
    };
    
    runner();
})();

Komodo fullscreen fix

Here's a a quick fix for a Komodo IDE bug that I reported a few weeks ago. 

I noticed a little while back that when you switch to full-screen mode in Komodo, the breadcrumb trail in the status bar disappears.  This seems like abug, as nothing else in the status bar goes away.  Why should the breadbrucms?

Anyway, a quick perusal of the komodo.css file and some tinkering using the Komodo Extension Developer add-on revealed an easy way to fix this.  All you need to do is create a new macro with the following text and set it to run on startup:

document.getElementById('breadcrumbBar').setAttribute('fullscreentoolbar', 'true');

That will add the appropriate attribute to the breadcrumb bar so that the CSS rule for "hide these when full-screen" won't catch it.  The breadcrumb bar is now visible in full-screen mode and seems to be fully functional.

Fixing fonts in XUL apps

Today I finally got fed up enough to fix the problem with fonts in XUL apps on my work desktop.

The problem and its solution are described in this post.  Basically, in XUL-based apps like Firefox and Komodo, the text would randomly distort.  It would usually happen when scrolling through a page or something like that that causes window redraws.  If I scrolled some more, or selected some text, it would go away.  And it only seems to happen on this particular system - my laptop doesn't seem affected.

Well, turns out it's a common issue.  In my case, I was able to fix it by going into the "about:config" page and changing the gfx.direct2d.disabled setting to true and restarting the app.  Turns out that while this page is well-known in Firefox, it's also available in Komodo.  You just need use the "preview buffer in browser" tool from the toolbar.  Just choose to preview the item in a Komodo tab and then enter "about:config" as the URL.  That will take you to the exact same config page you see in Firefox.

Finally upgraded to Komodo IDE

Well, I finally did it - I shelled out for a license of Komodo IDE.  I've been using Komodo Edit on and off since about 2007, but had never needed the extra features of the IDE to justify the $300 price tag.  But last week ActiveState had a one-week $100 off sale, so I decided to try it out again and ended up deciding to make the purchase.

My Komodo IDE setup

Part of what motivated me to give Komodo IDE another shot after getting along fine with Komodo Edit for so many years (aside from the price, of course) is my new-ish job.  It turns out that Eclipse is fairly popular among the Pictometry engineers, despite the fact that they're a pretty smart bunch (I'm not a fan of Eclipse).  Thus many of them take integrated debugging for granted, so on a few occasions I've been told to debug an issue by "just stepping through the code."  And to be fair, there have been a few bugs I've worked on where integrated debugging genuinely would have been useful.  Perhaps this is due to the fact that our internal back-end framework is significantly more Java-like than most code-bases I've worked on (but that's another post entirely).

Of course, that's not all there is to Komodo IDE.  There are plenty of other nifty features, such as the regex testing tool, structure browser, integrated source control, and a number of other things.  So when you put them all together, it's a pretty good value, especially at the sale price of $195.  And with the cool new stuff in Komodo 8.5, I have to say I've pretty much lost interest in trying out new editors.  The ActiveState team did a really nice job on the latest version.

Komodo TabSwitcher extension

I finally had a "new tech" adventure last week - I dabbled in Mozilla extensions for the first time.

I've been using ActiveState's Komodo Edit as my primary editor for PHP, Python, and JavaScript for the last few years. One of the extensions I always used was the TabSwitcher. I've found that I depend on that extension even more heavily now that I'm with deviantART simply because of the size of our code-base. While the Fast Open extension is great and has similar functionality, it simply doesn't fill the same role for me. Our code-base has thousands of file, many of which have similar names, which results in Fast Open slowing down and giving me too many results to be useful. Because TabSwitcher operates on a much smaller data set, it's much better for the common case where I have 20 or 30 tabs open and am actively switching back and forth between 8 or 10 of them.

The only problem is that TabSwitcher isn't compatible with Komodo 7. That's actually part of the reason I hadn't bothered to upgrade Komodo on my work computer yet. So I decided to remedy that by porting it to Komodo 7. While I was at it, I added a couple of small enhancements, such as updating the bookmark list when a bookmark is added.

You can download the extension here:
tabswitcher-1.0.0-ko.xpi
If you want to look at the source, it's in my Mercurial repository here:
http://hg.skepticats.com/tabswitcher/

This was my first exposure to XUL or Mozilla add-ons, so hopefully everything will work the way it should. I haven't seen any problems so far, at least.