Komodo

Another Ruby debugging FAQ: the .gem directory

Question: 

Why do I get the error message "ruby-debug-base could not be loaded", even after I've run `gem install ruby-debug-base`?

Answer: 

First, make sure that you've removed Komodo's own ruby-debug-base. You'll find it at /.../dbgp/rubylib/1.8 -- You can either rename that directory to something like "hide-1.8", or remove it. If you're running Ruby 1.9, this won't be an issue. We shipped ruby-debug-base as a favor, but with hindsight, I've begun to think this was the wrong decision. Back in the days of Ruby 1.8.4, not everyone had gem installed. Now it's standard issue on OS X, and easy enough to install.

Second, make sure there aren't any ruby-debug-base instances lurking in your .gem directory -- Ruby picks these in preference to the global gems.

If that doesn't help get your debugger working, along with the other tip in
http://community.activestate.com/faq/rails-debugging-triggers-internal-e...,
please drop me a line via support@activestate.com.

- Eric

Rails debugging triggers an internal error message

Question: 

When I try to debug Rails apps or unit tests in Komodo, I get an error message "INTERNAL ERROR!!! You have a nil object when you didn't expect it!" instead of breaking.

Answer: 

The problem is that a couple of Rails files are now loading ruby-debug-base whether it's requested or not. The result is that a mixture of objects in the Debugging module are loaded, and they conflict.

I submitted a patch at https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/2895 requesting that Rails loads the debugging environment only if it hasn't been loaded yet. I don't know if the patch has been applied to trunk yet, but it's an easy fix:

Find the two files in either your gem or vendor area:

actionpack/test/abstract_unit.rb
railties/lib/test_help.rb

Find these lines:

begin
  Debugger.start
rescue LoadError
  # Debugging disabled. `gem install ruby-debug` to enable.
end

and change the 'end' to

end unless defined? Debugger

Getting Komodo to remember the Debugging Options fields

Question: 

Every time I debug the same file, I have to re-enter the
directory in the Debugging Options field. How can I get
Komodo to remember it?

Answer: 

This is due to bug http://bugs.activestate.com/show_bug.cgi?id=80940,
in which Komodo uses the project's specific configurations, rather
than the "global" ones associated with each file.

The usual workaround is to make sure that you select a different
project, so the active project doesn't contain the file you're
trying to debug.

Komodo 5.2 features

Product: Komodo | tags: komodo 5.2 release features

This is an overview of the major items included in the Komodo 5.2 release.

Performance and Stability Improvements

The underlying Mozilla source code has been updated in Komodo, which has led to better security and stability of the Komodo platform as a whole.

Numerous performance improvements have been made to Komodo, in order to make Komodo speedier in the tasks it performs, such as when working on large files:

  • Komodo will now automatically style very large html documents as text in order to support faster edits and re-displaying of the document
  • the find search speed has been increased, making it faster to search your documents
  • the Rx Toolkit is now much faster when parsing results

PHP 5.3 support

Komodo now has started supporting PHP 5.3 in the following ways:

  • Code Intelligence
    • Code browser and sectionlist support for namespaces (IDE only)
    • Code completions for /Namespaces
    • Syntax colorizing of latest keywords ("namespace", "use", "as", etc...)
  • PHP Debugging
    • Improved debugger wizard for the first time setup
    • Updated xdebug builds to support PHP 5.3

Primary language preferences

It is now possible configure your primary languages that you use inside of Komodo.

Komodo's "Languages" preferences provides the interface to change the primary/secondary languages which are shown in the various language menus.

Sub-language background colors

It is now possible to give sub-languages a different background color. For example, when editing a HTML file you can set the JavaScript background color to be green and all the JavaScript code will appear as green section block:

In Komodo's "Fonts and Color" preferences, in the "Lang-Specific" tab navigate to the sub-language you wish to customize (in this example it's JavaScript) and then enable the "Use a different background color when used as a sub-language" checkbox and change the color appropriately.

View HTML Source

If you drag/drop a web url onto Komodo (http://, https://), Komodo now offers to view the source contents of this web page. This is convenient for checking the underlying HTML source code of web pages.

When you select the "View Source" button, the web URL will be downloaded and then opened in a Komodo editor tab as a read-only file.

SCC History searching (IDE only)

The SCC history dialog now has a search facility:

This search textbox filters the history items, word-by-word, matching on any field (date, user, message, etc...) of the visible history columns.

Bug Fixes

A lot of commonly requested/encountered Komodo bugs have been fixed in this release, such as:

  • can now "chmod" remote files
    (bug 29688)

    The file-properties page now has a "Change" button in order to change the file permissions.

  • scc: commit dialog now remembers previous commit messages
    (bug 29688)

    There is now a drop-down menu in the top-right of the commit dialog that provides the ability to select a previous commit message.

  • scc: support for using external diff tools
    (bug 74288)

    There are now per scc preferences to state whether the scc diff is handled through an external editor - so that Komodo does not show it's own internal diff dialog and/or wait until external diff is completed.

  • can now choose the color of find highlighting (and other indicators)
    (bug 81899)

    In Komodo's "Fonts and Colors" preferences, there is now an "Indicators" tab in which you can change the color of various Komodo indicators, such as the find highlighting color.

  • scc: the add new file operation will also add any necessary parent directories
    (bug 74774)
  • null bytes: Komodo can again open edit and save files that contain null bytes
    (bug 35678)

Getting your hands on the 5.2 Komodo release

You can download the Komodo releases here:
http://downloads.activestate.com/Komodo/releases/

Other Komodo releases

Setting up a new Komodo IDE formatter

Question: 

How do I create a new Komodo code formatter for a given language?

Answer: 

Komodo's code formatting system can be used to launch external code formatting applications on your source code.

  • Go to Komodo's formatter preferences
    You can use Komodo's Edit->Preferences to bring up the Komodo preferences dialog, then select the Formatters category.
  • Create new formatter
    Use the green (+) button to start creating a new formatter. Fill in the Name and Language fields and then in the Formatter menu select the Other Formatters->Generic command-line formatter. This will show further configurable options to customize the formatter command. Generally this will be the name of the executable (example "tidy") and the options that are passed to this executable. The actual code to be formatted will be passed via stdin.
  • Example Language Formatters

How to change Komodo auto updating

Question: 

How do I change Komodo to use a different build, such as a nightly build?

Answer: 

The simplest way to change Komodo builds is through the Komodo auto-update facility, where you can update between the latest "release", "beta" and "nightly" versions of Komodo. To do this, you'll need to locate the channel-prefs.js file in your Komodo installation, on Windows and Linux this file is here:

INSTALLDIR/lib/mozilla/defaults/pref/channel-prefs.js

and on Mac OS X here:

INSTALLDIR/Contents/MacOS/defaults/pref/channel-prefs.js

It is a very simple file that looks like this:

// Valid values are "release", "beta" and "nightly".
pref("app.update.channel", "release");

Change the value to whatever you wish to use (i.e. "nightly"), restart Komodo and then use Komodo's Check for Updates menu to update to the required build.

Note: You can change back your auto-update channel at anytime, but there is no un-update functionality, example:

  • You start at Komodo release 5.1.0 (build 27487)
  • Change to "nightly" channel, restart and auto-update to nightly 5.1.1 (build 27621)
  • Change to "release" channel, restart. Your still at build 27621, the auto-update will only trigger again when the next release build of Komodo is made (i.e. 5.1.1 final)

More information on the Komodo auto-update system is available in Trent's blog:
http://trentm.com/blog/archives/2008/03/03/komodo-aus/

Adding a Komodo hyperlink handler

Product: Komodo | tags: hyperlink

The Komodo hyperlink handling is useful for providing a customized action for the given text underneath the Komodo cursor, see here for an overview:
http://community.activestate.com/komodo-51-features#hyperlinks

You can also add your own customized hyperlink handler. Below is an example of adding a custom regular expression hyperlink handler to Komodo.

You will need to create a Komodo JavaScript macro that triggers on Komodo startup, with the following base contents:

// This handler will match the given pattern and when clicked, will
// try to open the URL: "http://foo.com/$1", where $1 is the regular
// expression match group 1. You can use $0 through to $9.
var myRegexHandler = new ko.hyperlinks.RegexHandler(
      "Name of your handler",
      new RegExp("pattern\\s(.*)", "i")  /* pattern match */,
      ko.browse.openUrlInDefaultBrowser  /* function, action taken */,
      "http://foo.com/$1"                 /* replacement string */,
      null                               /* Supported language names */,
      Components.interfaces.ISciMoz.INDIC_PLAIN, /* indicator style */
      RGB(0x60,0x90,0xff));                      /* indicator color */
ko.hyperlinks.addHandler(myRegexHandler);

Now, the goto definition handler may be beating you to the punch (because hyperlink handlers are checked in the order they were originally added and only one can win). So, you may want to bump up your handlers place in line, example:

var gotoHandler = ko.hyperlinks.getHandlerWithName("Goto Defintion");
ko.hyperlinks.removeHandler(gotoHandler);
ko.hyperlinks.addHandler(myRegexHandler);
ko.hyperlinks.addHandler(gotoHandler);

For further details on the regular expression hyperlink class, see the source code:
http://svn.openkomodo.com/openkomodo/view/openkomodo/trunk/src/chrome/ko...

Komodo 5.1 features

Product: Komodo | tags: komodo 5.1 release features

This is an overview of the major items included in the Komodo 5.1 release.

Find Highlighting

Komodo will now highlight the search term (in yellow), indicating where the matches are in your document(s). Komodo will also highlight the replacements that you make when using the find and replace dialog.

See Trent's blog to see a short screencast and more details on this feature.

History

The "History" feature for Komodo is similar to a web browser's history, it allows you to quickly walk between your code movements and actions.

See Trent's blog post for additional information:
http://trentm.com/blog/archives/2009/02/04/history-feature-in-komodo-510...

Hyperlinks

When you hold down the Ctrl key (Cmd key on the Mac) and move the mouse around, Komodo will underline the interesting (interactable) points under your mouse cursor. This can be used for showing things like the goto definition search term, and when clicking on the hyperlink it will perform the goto definition command. Other cool uses for this feature are CSS color previewing and color picker interaction (screenshot below) as well as being able to click on a http link in the editor and have it open inside your browser.

Check out Trent's blog for more details on the Komodo hyperlink handler:
http://trentm.com/blog/archives/2009/03/13/hyperlinks-in-komodo-510b1/

as well, you can also add your own custom hyperlink handlers, check out this article:
http://community.activestate.com/adding-komodo-hyperlink-handler

Fast Open

The fast open dialog provides a quick and easy way to access your files. You can use the dialog to list and filter the files within your current working directory, files within the current project, recently opened/closed files as well as being able to switch to a currently opened file.

The default key bindings for the fast open dialog are:
* Ctrl+Shift+O (on Windows and Linux)
* Cmd+Shift+O (on the Mac)

A Fast Open screencast is shown here:
http://www.vimeo.com/3825622

Linux 64-bit (x86_64) builds

Finally Komodo has builds for running natively on 64-bit Linux. This means no more mucking around trying to find 32-bit compatibility libraries on Linux, yay!

Better localization support

Davide Ficano (aka Dafi) has been working hard in the previous months on adding better localization support for Komodo, involving a number of patches to the OpenKomodo tree. These have now been checked in to the Komodo trunk and improved Komodo localization is now possible. Thanks for the great work Dafi!

Download it

Komodo downloads are available here:
http://downloads.activestate.com/Komodo/releases/
There are also nightly updated builds available here:
http://downloads.activestate.com/Komodo/nightly/

Documentation and Bug fixes

For a full set of release notes and Komodo 5.1 documentation, see the online pages:
http://docs.activestate.com/komodo/5.1/

Other Komodo releases

Getting / Setting a Komodo preference

Question: 

How do I change a specific Komodo preference?

Answer: 

Komodo's uses a number of preferences to control how the program is run. Most preferences are modified through the Komodo preferences dialog, though there are some that are not exposed through the UI.

The preferences are based on a default "prefs.xml" which can be found inside your Komodo installation directory, and then any preference changes to the base preferences are stored into your Komodo user data directory. This file stores a number of different preference types:

You can see the base OpenKomodo (Komodo Edit) "prefs.xml" file here:
http://svn.openkomodo.com/openkomodo/view/openkomodo/trunk/src/prefs/pre...

These preferences can be modified by changing the XML files manually (and then restarting Komodo), or can be changed using the Komodo API, such as through a JavaScript macro.

Some example JavaScript macros (which can be added to your Komodo toolbox) for changing preferences are listed below:

Getting a boolean preference

var pref_name = ko.interpolate.interpolateStrings(["%(ask: Boolean pref name)"]);
if (pref_name) {
    var prefs = Components.classes['@activestate.com/koPrefService;1'].getService(Components.interfaces.koIPrefService).prefs;
    if (prefs.hasBooleanPref(pref_name)) {
        alert("'" + pref_name + "': " + prefs.getBooleanPref(pref_name));
    } else {
        alert("No boolean pref exists for '" + pref_name + "'");
    }
}

Setting a boolean preference

var pref_name = ko.interpolate.interpolateStrings(["%(ask: Pref name)"]);
if (pref_name) {
    var pref_value = ko.interpolate.interpolateStrings(["%(ask: Value: 1)"]);
    if (pref_value !== null) {
        var prefs = Components.classes['@activestate.com/koPrefService;1'].getService(Components.interfaces.koIPrefService).prefs;
        //dump("Setting pref '" + pref_name + "' to '" + pref_value + "'\n");
        if (pref_value == "1" || pref_value.toLowerCase() == "true") {
            prefs.setBooleanPref(pref_name, true);
        } else {
            prefs.setBooleanPref(pref_name, false);
        }
    }
}

Setting a string preference

var pref_name = ko.interpolate.interpolateStrings(["%(ask: Pref name)"]);
if (pref_name) {
    var pref_value = ko.interpolate.interpolateStrings(["%(ask: Value)"]);
    if (pref_value !== null) {
        var prefs = Components.classes['@activestate.com/koPrefService;1'].getService(Components.interfaces.koIPrefService).prefs;
        //dump("Setting pref '" + pref_name + "' to '" + pref_value + "'\n");
        prefs.setStringPref(pref_name, pref_value);
    }
}

Setting a number preference

var pref_name = ko.interpolate.interpolateStrings(["%(ask: Pref name)"]);
if (pref_name) {
    var pref_value = ko.interpolate.interpolateStrings(["%(ask: Value)"]);
    if (pref_value !== null) {
        var prefs = Components.classes['@activestate.com/koPrefService;1'].getService(Components.interfaces.koIPrefService).prefs;
        //dump("Setting pref '" + pref_name + "' to '" + pref_value + "'\n");
        prefs.setLongPref(pref_name, parseInt(pref_value));
    }
}

API methods on a Komodo PreferenceSet

To see a full list of API methods when writing a JavaScript macro, you'll need to query the preference into a Komodo preference set, example:

var prefs = Components.classes['@activestate.com/koPrefService;1'].getService(Components.interfaces.koIPrefService).prefs;
var prefset = prefs.QueryInterface(Components.interfaces.koIPreferenceSet);
prefset.<|> // Completions seen here.

The Many Ways of Extending Komodo

Product: Komodo | tags: extensions macros source hacking

Every once in a while I write a short overview on the various ways you can make Komodo work the way you want. This article's mostly for the benefit of recent arrivals to the Komodo way of slinging code, but since I've picked up a few things since the last time I wrote this, it might be worth hanging around a bit if you're a vet.

Komodo is no black box. It's based on Mozilla, which means most of the interesting code is shipped as part of the product. Here are a few different ways you can take advantage of this to make Komodo work the way you want it to, or at least embark on that interesting journey.

First, it helps to know where the source is. There's a lot of code, spread out in various areas, but the two main parts of the code are based off something I'll call "mozhome" (which is &lt;installDir>/lib/mozilla on Windows and Linux, and /Applications/Komodo.app/Contents/MacOS on OS X). While there are a few other areas, the main Komodo code is split into the front-end, in these two directories:

  mozhome/chrome/komodo.jar
  mozhome/chrome/xtk.jar

and the back-end, in these two areas:

  mozhome/python/komodo
  mozhome/components/ko*.py

To explore the chrome code, copy the jar file to a separate directory (it should be empty), unzip it there, and at a later point, if you make modifications you can zip it up and replace the shipped komodo.jar file with your own.

For both Python and chrome files, changes will automatically be picked up by Komodo on restart.

If you know an identifier name, or a string of text, you can search for it quickly at http://grok.openkomodo.com/source/xref/openkomodo/trunk/. Note that this is the code base for Komodo Edit. You can work with features specific to Komodo IDE, but you'll only have local searching. Also if you're using Komodo IDE but looking at the Komodo Edit source, line numbers are different because the files have different licenses at the start of their source. Finally, some of the source files go through preprocessing before being packaged into the Komodo distro, and their name will contain an extra extension such as ".p" or ".unprocessed".

Macros

Now that we've covered where the code is, here's how to extend it.

The quickest way to get started is by using the Macro Recorder, saving the recorded macros in the toolbox, and using them. These often work, but some operations aren't recorded (such as setting items in a dialog box), and due to the way the macros are serialized, they don't always work once they're saved in the toolbox. In particular, macro lines that work with the editor by manipulating Komodo commands should use the Komodo editor API directly.

For example, if you record a sequence of moving down three lines, and to the right by two characters, you'll get this macro:

komodo.assertMacroVersion(2);
if (komodo.view) { komodo.view.setFocus() };
komodo.doCommand('cmd_lineNext')
komodo.doCommand('cmd_lineNext')
komodo.doCommand('cmd_lineNext')
komodo.doCommand('cmd_right')
komodo.doCommand('cmd_right')

If you're thinking of writing macros (or extensions) that work with the editor, it's never too soon to start working with the editor API. It's based on Scintilla, so you can find plenty of documentation on it, as well as in Komodo's help. The above macro would be rewritten like so:

var scimoz = ko.views.manager.currentView.scimoz;
scimoz.lineDown();
scimoz.lineDown();
scimoz.lineDown();
scimoz.charRight();
scimoz.charRight();

Think of the doCommand statements that Komodo generates for you as scaffolding, which you eventually should replace before you're ready to unleash your macros on the world.

Next, macros can be written in either JavaScript or Python. Usually if you're interacting with the front-end, JavaScript means you can manipulate it more directly. However, sometimes there are common libraries in Python that make it too compelling. For example, I have a macro I use constantly that lets me reformat single-line paragraphs into blocks of text more suited for people who read email with older text-based agents. Here's the code:

    import textwrap
    paragraphs = re.split(r'\r?\n\r?\n(?=.)', text)
    lines = []
    for p in paragraphs:
        if longLine_re.search(p):
            lines += textwrap.wrap(p)
        else:
            lines += re.split('\r?\n', p)
        lines.append(eol)

You might be wondering why I'm talking about email packages in an article on hacking Komodo, which isn't known for its mail capabilities. It turns out this macro uses the clipboard for its I/O. I'll show the code, as it shows how to interface Python with Mozilla:

class ClipboardWrapper():
    def __init__(self):
        self.clipboard = components.classes["@mozilla.org/widget/clipboard;1"].getService(components.interfaces.nsIClipboard)
        self.transferable = components.classes["@mozilla.org/widget/transferable;1"].createInstance(components.interfaces.nsITransferable)
        self.transferable.addDataFlavor("text/unicode")
       
    def _getTextFromClipboard(self):
        self.clipboard.getData(self.transferable, self.clipboard.kGlobalClipboard)
        (str, strLength) = self.transferable.getTransferData("text/unicode")
        return str.QueryInterface(components.interfaces.nsISupportsString).data[:strLength/2]

    def _copyTextToClipboard(self, text):
        data = components.classes["@mozilla.org/supports-string;1"].createInstance(components.interfaces.nsISupportsString)
        data.data = text
        self.transferable.setTransferData("text/unicode", data, len(text) * 2)
        self.clipboard.setData(self.transferable, None, self.clipboard.kGlobalClipboard)

This code also shows you how to interface with the Mozilla API via XPCOM. It turns out this is actually slightly easier from Python than from JavaScript, as the PyXPCOM library knows how to manage out-variables. In JavaScript you'd have to write the above getter like so:

var str = {};
var strLength = {};
this.transferable.getTransferData("text/unicode", str, strLength);
return str.value.QueryInterface(Components.interfaces.nsISupportsString).
       data.substring(0, strLength.value / 2);

For some reason, the Python XPCOM library spells "Components" with a lower-case "c". If you're getting tripped up by this, you can get around it with this line:

from xpcom import components as Components

If you're thinking I've left out a lot of material, you're right. The Komodo API is large, and the Mozilla XPCOM library is larger.

It's also worth mentioning that Komodo picks up changes to macros immediately, as opposed to any other kind of change.

Macro Documentation

Both macros in JavaScript and Python let you take advantage of a higher-level Komodo API, documented at http://docs.activestate.com/komodo/5.0/macroapi.html (note that these functions are available only inside macros). You can find info on the standard Komodo API at http://docs.activestate.com/komodo/5.0/komodo-js-api.html

Debugging Macros

There might be an easy way of debugging macros, but I doubt it. Both JavaScript and Python macros are run with a single eval block (exec for Python). The JavaScript debuggers I've tried won't step into these eval blocks. You can't easily use print statements either, and writing to the Komodo output window is more complicated than one would want for a quick print statement. Instead I use the Komodo version of Ted's Extension Developer Extension, available here, and in particular use the JavaScript shell to test out macro lines incrementally. It might look like you can only enter one line at a time in the shell. To enter a block of code, you can either press Shift-Return at the end of each line, or better still, write the code in Komodo, select and copy it, and paste it into the shell, which knows how to handle multi-line insertions.

The extension is also a reasonable way of interactively exploring much of Komodo's front-end code. Type "ko." followed by two tabs to get a list of the main components in the "ko" namespace. Most of the time you'll be working with ko.views for editor files, and ko.projects.

Restyling Komodo

While you could modify the CSS files in komodo.jar, Komodo supports the same mechanism other Mozilla apps use, and you can simply override Komodo's default settings by providing a "userChrome.css" file in your profile. See http://community.activestate.com/faq/customizing-the-komodo-ui for more info.

Extensions

Once you've reached the limits of what you can do with macros, the next step is to write an extension. In Komodo this gives you access to adding new parts to the UI, new menu items, new sidebars. Most of the resources I mentioned above are useful for extension writing as well.

The "Komodo Extension" project template will help you get started, but like recorded macros, it's more of a scaffold generator than a code generator.

It's definitely worth spending time reading the source of extensions you use, to understand how they're assembled. The best source for Komodo extensions is at http://community.activestate.com/addons. Extensions end with ".xpi", so the host application (that's Komodo here, but also Firefox and other Mozilla apps) knows how to load them when they try to open them, but they're just zip files.

When you're working on an extension, you might find the following cycle gets old fast:

  • Edit and save extension source
  • Rebuild and rezip
  • Reinstall the extension into Komodo
  • Restart Komodo
  • Test changes

Here's a useful shortcut for Mozilla extensions I wish I had learned years ago. These extensions live in the application profile directory, which is something like /5.0/host-hostname/XRE/extensions. Let's say you're working on an extension called foo@mycom.org -- normally installing an extension in Komodo will create a directory called "foo@mycom.org" in the extensions directory, and the contents of this directory will contain the extension. However, you can use a platform-independent shortcut -- delete the installed foo@mycom.org directory (you have the source for this elsewhere, right), and replace it with a file with the same name, "foo@mycom.org". Its contents should be one line containing the absolute path to the extension code (the Komodo extension project template will create this automatically). Now you don't need to reinstall your extension each time. Instead the work cycle is now:

  • Edit and save extension source
  • Rebuild
  • killall komodo-bin (or use the Task Manager on Windows to quickly close Komodo). When you're in this cycle you most likely don't want to take the extra time Komodo needs to shut down gracefully.
  • Restart Komodo
  • Test changes

Same number of steps, but you no longer need to do the extension install dance.

There is much more on writing extensions, but this is supposed to be a short article.

Hacking and Patching

As you write increasingly ambitious macros and extensions, you'll no doubt have spent some time reading Komodo code, and found some opportunities to make improvements.

The main problem with this is that while macros and extensions live across versions (although extensions will need to be reinstalled, and macros will often need to be exported into a package, and then reloaded in the new version), changes to the Komodo code base will remain with earlier versions. At this point you're advised to submit your patches -- see http://www.openkomodo.com/participate for details.