Welcome, guest | Sign In | My Account | Store | Cart

When editing a group of similar lines, it's very convenient to be able to press down-arrow and move to the same starting column position on the next line. (See an example at http://community.activestate.com/forum/vertical-editing ).

This code is for a Komodo 6 macro -- possibly the only tweak necessary to make it work on Komodo 5 is by commenting out the "macro.save()" code, but I haven't tested it. The discussion below will talk about how to use it.

JavaScript, 56 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
var view = ko.views.manager.currentView;
var scimoz = view.scimoz;
var methodName = "*ext*verticalEditing";
if (!(methodName in view)) {
    view[methodName] = function(event) {
        if (event.keyCode == event.DOM_VK_DOWN) {
            var currentLine = scimoz.lineFromPosition(scimoz.currentPos);
            if (currentLine >= scimoz.lineCount - 1) {
                toggleOff();
                return;
            }
            var targetPos = scimoz.positionFromLine(currentLine + 1) + methodObject.columnPos;
            scimoz.gotoPos(targetPos);
            event.preventDefault();
            event.stopPropagation();   
        } else if (event.keyCode == event.DOM_VK_ESCAPE) {
            toggleOff();
        }
    };
    view[methodName].active = false;
    var macro = ko.macros.current;
    view[methodName].macro = macro;
    view[methodName].orig_iconurl = macro.iconurl;
}
var methodObject = view[methodName];

function toggleOn() {
    view.addEventListener('keypress', methodObject, true);
    methodObject.active = true;
    if (komodo.view) {
        komodo.view.setFocus();
        if (komodo.view.scintilla) { komodo.view.scintilla.focus(); }
    }
    methodObject.columnPos = scimoz.getColumn(scimoz.currentPos);
    methodObject.macro.iconurl = 'chrome://komodo/skin/images/leftarrow.png';
    methodObject.macro.save();
    window.addEventListener('current_view_changed', toggleOff, false);
    window.addEventListener('view_closed', toggleOff, false);
    //dump("listen for a keypress event for column: " + methodObject.columnPos + "\n");
}

function toggleOff() {
    //dump("stop listen for a keypress event\n");
    view.removeEventListener('keypress', methodObject, true);
    window.removeEventListener('current_view_changed', toggleOff, false);
    window.removeEventListener('view_closed', toggleOff, false);
    methodObject.active = false;
    methodObject.macro.iconurl = methodObject.orig_iconurl;
    methodObject.macro.save();
}

if (!methodObject.active) {
    toggleOn();
} else {
    toggleOff();
}

Some other editors implement "vertical-editing". Komodo doesn't ship with it, but this macro shows how you can stretch the editor using the Komodo API.

There are a few interesting aspects about this macro, and also at least one bug (to be discussed later).

First, I want to intercept the down-arrow, but only when you're typing in the editor window. I can create a function to do this, and pass it as the method to the view's event listener. Since I want to avoid colliding with other properties on the view, I give it an unlikely name of *ext*verticalEditing, which means it can be invoked only with JavaScript's object[...] notation, and not its dot notation.

The macro takes advantage of the fact that JavaScript functions are objects, and can store arbitrary properties. I store several of these custom properties on the method I added to the view, including whether vertical editing is active or not, the current macro object, and the macro's original icon. By storing these values, I can easily change the macro's icon while it's active, and then switch it back.

Once I'm done editing values in a particular block of data, I can click on the macro again, and down-arrow reverts to its default meaning.

There are at least two bugs in this macro:

  1. I assume the pattern of tabs and spaces is the same in each line in the block, since the multiple lines were most likely created by multiple pastes, which would have preserved tabs. A solution is left as an exercise to the interested reader, or you can just avoid inserting tabs into your programs.

  2. The macro blindly tries to move to column X of each line, even for those lines that have fewer than X characters in them. It would make sense for the macro to toggleOff() at this point. Next version...

Cool tip from Troy: add ESCAPE handling to the eventListener, to turn off down-arrow handling.

2010-09-29 fix: Add event listeners to toggle off editing whenever we move away from the buffer.

5 comments

Stan Angeloff 13 years, 7 months ago  # | flag

I am a bit lost, isn't that already available out-of-the-box using the Alt key? I have done it so many times -- hold down Alt, use the arrow keys to extend the selection up or down. Type or delete backwards and lines get updated.

Álvaro G. Vicario 13 years, 7 months ago  # | flag

@Stan, the feature you describe makes the same edition in all lines (which is a cool feature indeed but it's something different).

Eric Promislow (author) 13 years, 6 months ago  # | flag

Stan, this feature in effect bookmarks a particular column on each line. Then when you press down-arrow, it moves to that position on the next line. This happens until you toggle the feature off (by re-invoking the macro), press ESCAPE, or hit the end of the file.

This macro also shows how to implement a "toggle macro" in Komodo:

  • maintain state
  • set macro icons dynamically
Stan Angeloff 13 years, 6 months ago  # | flag

These powerful macros should really be part of the Komodo distribution. If not as part of the editor itself, perhaps under the Sample toolbox. There is sooo much goodness you guys put together as macros, it would really benefit the editor if it shipped with it.

Eric Promislow (author) 13 years, 6 months ago  # | flag

Thanks, Stan. A lot of this code does make it into Komodo eventually, but this particular macro wasn't ready for prime time: I knew about 2 bugs when I first published it, and have already found at least two others.

Created by Eric Promislow on Thu, 23 Sep 2010 (MIT)
JavaScript recipes (69)
Eric Promislow's recipes (11)

Required Modules

  • (none specified)

Other Information and Tasks