Kate and Regular Expressions

One of the main reasons, why I finally landed at Vim as editor was the lack of decent regular expression support in all other editors I used so far (except, of course, Emacs).

That includes especially Notepad++ on Windows and gedit and Kate on Linux. My main criticism is, that in none of the latter three you can consistently and simply search for strings with newlines. Or, if you can, you cannot replace the text. Or you can only search with either umlauts or line breaks, …

Actually, it seems, that the situation became way better meanwhile than when I made the switch in summer ’09. The current Kate can evaluate statements of the form s/pattern/replacement/. Ironically, some features of this newly tuned command line have a clear root in the ed/ex/vi world. They even introduced an vi mode.

But back then I was stuck with KDE 3 and an older Kate. For that version I found a solution, that allowed me to use the full power of regular expressions that come with JavaScript. Since Kate can be scripted (which has been spent a major overhaul, since I looked at it), I used this power to access the JS regexp engine.

An important drawback of Kate’s then scripting engine was the inability to pass parameters to a script, so I had to work around that by putting the regular expression in the file to be edited. It’s nasty, but at least it works.

For Kate to find the user script, it needed a .desktop file at ~/.kde/share/apps/katepart/scripts/re.desktop, that read like this:

[Desktop Entry]
Encoding=UTF-8
Name=re
Comment=REAL search and replace with regexps
X-Kate-Command=re
X-Kate-Help=<p>REAL search and replace with regexps. Write a regular expression in the form <code>/search/replace/</code>, select it and run this script. <strong>Note:</strong> The regular expression will be erased from the document. If you don't want this, prefix it with an <code>s</code>.</p>

The actual JavaScript code lives then in ~/.kde/share/apps/katepart/scripts/re.js:

/**
* REAL search and replace with regexps
*/

(function () {
if (view.hasSelection ()) {
var pattern = view.selection();

// whether the regexp itself should be deleted
var delete_regexp = true;
if (pattern.substr(0,1) == "s") {
delete_regexp = false;
pattern = pattern.substr(1);
}

// find modifiers
var modifiers = "";
if (pattern.search(/[gim]{1,3}$/) > -1) {
modifiers = pattern.replace(/^.*?([gim]{1,3})$/, "$1");
pattern = pattern.replace(/^(.*?)[gim]{1,3}$/, "$1");
}

// find the delimiters
var delim = pattern.substr(0, 1);
if (pattern.substr(pattern.length-1, 1) !== delim) {
debug("ending delimiter missing.");
return false;
} else if (pattern.substr(1, pattern.length-2).indexOf(delim) < 1) {
debug("middle delimiter missing.");
return false;
}

// compile the regexp
var regexp = new RegExp(pattern.substr(1, pattern.substr(1)
.indexOf(delim)), modifiers);
var replacement = pattern.substring(pattern.substr(1)
.indexOf(delim)+2, pattern.length-1);

// remove the regexp, if wanted
if (delete_regexp) {
view.removeSelectedText();
}

// apply the regexp
var fulltext = document.textFull().replace(regexp, replacement);
document.setText(fulltext);
return true;
} else {
debug("No regexp selected.");
return false;
}
})();

Kate will execute the script under the name “re”. It works like this: You write the regular expression directly in the file, e.g., /foo/bar/g, then highlight it. After pressing F7 the command line shows up, where you enter re. The highlighted text vanishes, and the regular expression is then applied to the whole text, replacing foo with bar.