ActiveBlog

How to add new commands to the OpenKomodo source
by Eric Promislow

Eric Promislow, December 10, 2007

A Komodo customer pointed out that our Emacs keybindings are missing sequences for the previous-paragraph and next-paragraph commands, where a paragraph is simply defined as a sequence of text delimited by one or more blank lines at either end (or a document boundary). Fortunately, Scintilla has primitives for moving to the previous and next paragraphs -- they don't behave identically to native Emacs behavior. Emacs moves the cursor between paragraphs, while Scintilla moves it to the start of each paragraph. Let's assume that we'll live with this difference -- here are the patches needed to add the commands.

It's easiest to work backwards. First we need to tie Komodo commands to Scintilla commands (defined in .../contrib/scintilla/include/Scintilla.iface):


Index: .../src/SciMoz/koScintillaController.p.py
===================================================================
--- koScintillaController.p.py (revision 12092)
+++ koScintillaController.p.py (working copy)
@@ -57,6 +57,8 @@
'cmd_fontZoomOut' : 'zoomOut',
'cmd_toggleOvertype' : 'editToggleOvertype',
#'cmd_newline' : 'newLine',
+ 'cmd_paraUp' : 'paraUp',
+ 'cmd_paraDown' : 'paraDown',
# #if WITH_VI_KEY_BINDINGS
'cmd_copyLine' : 'lineCopy',
'cmd_homeAbsolute' : 'home',

Komodo works with a set of abstract commands. They're defined here:


Index: .../src/chrome/komodo/content/commandsOverlay.unprocessed.xul
===================================================================
--- commandsOverlay.unprocessed.xul (revision 12092)
+++ commandsOverlay.unprocessed.xul (working copy)
@@ -581,6 +581,14 @@
id="cmd_beginningOfWordExtend" key="key_cmd_beginningOfWordExtend"
oncommand="ko.commands.doCommand('cmd_beginningOfWordExtend')"
desc="&editorSelectToBeginningOfWord.desc;"/>
+ <command
+ id="cmd_paraUp" key="key_cmd_paraUp"
+ oncommand="ko.commands.doCommand('cmd_paraUp')"
+ desc="&editorParaUp.desc;"/>
+ <command
+ id="cmd_paraDown" key="key_cmd_paraDown"
+ oncommand="ko.commands.doCommand('cmd_paraDown')"
+ desc="&editorParaDown.desc;"/>
<!-- The remaining ones are only available when a read/write
editor has focus: optimization possible -->
<command

The key attributes define the unique key name for each key binding,
and don't need to be defined elsewhere.

Finally, the entities need to be defined. These are the strings users see in the [Preferences|Editor|Key Bindings|Commands] list, and are defined in DTD files to take advantage of Mozilla's localization infrastructure:


Index: .../src/chrome/komodo/locale/en-US/komodo.dtd
===================================================================
--- komodo.dtd (revision 12092)
+++ komodo.dtd (working copy)
@@ -94,6 +94,8 @@
<!ENTITY editorMoveToPreviousMarkInMarkRing.desc "Editor: Move to previous mark in mark ring">
<!ENTITY editorPageDown.desc "Editor: Page Down">
<!ENTITY editorPageUp.desc "Editor: Page Up">
+<!ENTITY editorParaUp.desc "Editor: Paragraph Up">
+<!ENTITY editorParaDown.desc "Editor: Paragraph Down">
<!ENTITY editorPaste.desc "Editor: Paste">
<!ENTITY editorPasteAndSelect.desc "Editor: Paste and Select">
<!ENTITY editorRedo.desc "Editor: Redo">

Rebuild, and you'll have the new commands. Making the commands work the way Emacs does will require a bit of coding, and exceeds the scope of the one-minute note this post is intended to be. See a method like "_do_cmd_linePrevious" in koScintillaController.p.py for an example.

Subscribe to ActiveState Blogs by Email

Share this post:

About the Author: RSS

Eric Promislow is a senior developer who's worked on Komodo since the very beginning. He has a M.Sc. in Computing Science from Queen's University and a B.Sc. in Biophysics from the University of Ontario. Before joining ActiveState, he helped create the OmniMark text-processing language.