MW

Spotlight: Kate Scripting

Hey ho everyone.

Dominik asked me to blog about a feature in Kate that is still (sadly!) pretty unknown and seldom used: Kate Scripting. As you should know you can script KatePart completely via JavaScript. As those articles explain, it’s rather simple to write functions and put them into a file to have them reusable. But what for those write-use-throwaway kind of cases, where you simply need to get a job done quickly and don’t want to go through the overhead of writing some full fledged, documented, action-binded, localized script?

Utility Functions and why JavaScript rocks

Note: Neither map nor filter will be shipped with 4.5 to my knowledge, sorry about that. But you can still use the each helper (see below) to achieve the same with a bit more typing…

Take a look at utils.js on current git master: http://gitorious.org/kate/kate/blobs/master/part/script/data/utils.js

Put a special note on the helper functions map, filter and each and how they are used to implement e.g. rmblank, [rl]trim and the other functions. Cool eh? And the best part, you can reuse them directly from inside KatePart to get a job done:

mail-style quoting

Lets assume you write an email or use something like Markdown or Textile and want to quote. You’ll have to prepend a few lines with the two chars ‘> ‘. Instead of copy’n’pasting like a maniac do this instead and save yourself some breath:

  1. press F7 to open the Kate command line
  2. write e.g. map "function(l) { return '> ' + l; }"
  3. execute

Note: When you don’t have anything selected, the whole document will get “quoted”.

remove lines that match a pattern

This is something everyone needs to do sooner or later, happened quite a few times to me already. I bet vim has some esoteric command I cannot remember and emacs has something like C-x M-c M-butterfly. But with Kate most users only see search & replace and forfeit to the command line. Well, now it’s again a good time to use the command line:

  1. press F7 again
  2. write e.g. filter "function(l) { return l.indexOf('myNeedle') == -1; }"
  3. execute

Now all lines that contain ‘myNeedle’ will get removed. Sure, this is “verbose” but assuming you know JavaScript it’s actually quite easy, expendable and - best of all - good to remember. At least for me, YMMV.

shortcuts

For simple cases I’ve now introduced a shortcut way of doing the above, that saves you even more typing, but is limited to simple evaluations like the ones above. If you need something fancy, you’ll have to stick to the type-intensive way. Aynhow, here’s the shortcut version of the two scripts:

  1. map "'> ' + line"
  2. filter "line.indexOf('myNeedle') == -1"

the guts: each (interesting for users of KDE 4.x, x < 6)

Both of the above are implemented using the each helper I introduced even before KDE 4.4 afair. If you are using KDE 4.5 and want to do one of the above, a bit more typing is required:

  1. for map, you write something like this:
    each "function(lines) { return lines.map(function(l){ /** actual map code **/ }); }"

  2. for filter you do the same but replace map with filter:
    each "function(lines) { return lines.filter(function(l){ /** actual filter code **/ }); }"

Conclusion

You see, it’s quite simple and powerful. I really love map-reduce and how easy it is to use with JavaScript. Hope you like it as well.

PS: I actually think about making it yet even easier, by allowing some syntax like this:map '> ' + line or filter line.indexOf('myNeedle') == -1, must take a look on how hard it would be (beside the need for extensive documentation, but hey we have the help command in the Kate CLI, who can complain now? :) Implemented

Bye

Comments

Want to comment? Send me an email!

Comment by Peg (not verified) (2011-10-11 01:16:00)

Was just looking for Kate Scripting info & found this. I need a rewrap feature & read that scripting may be the answer. I use Kate’s command line a lot (F7), especially the sed-like command. Another way to add the “>” on each line is to use regular expressions; Type ctrl-r, then in the Find textbox enter “^” and in the Replace textbox add “> “, and change mode to Regular Expression. In this specific example the email highlighting file could have a section and the user could use ctrl-d. The second example above, I usually resort to sed outside of Kate to delete lines. It’s helpful to know it can be done within Kate. It would be nice if there was some pop-up help or some integrated tool for Kate Javascript API that would aid newbies “build” their scripts.

Comment by GreyGeek (not verified) (2010-07-29 22:04:00)

During the last five year of work, I was using MS VS C++ 6.0 with Qt Integration to do in-house client-server programming with Qt4 & C++. Waiting for MSVC to finish a compile was getting more painful as the project grew. I decided to switch to my Linux side and use Kate with Kdbg. I found I could do up to 5 compiles a day on Linux, compared to 2 o3 on Windows. The improvement in efficiency was in the speed of Kate and the speed of the g++ compiler. When I reached a milestone while developing on Linux against a PostgreSQL backend, I’d move the source to my Windows side, recompile and deploy. Compiler defines handled the difference in syntax between Oracle and PostgreSQL, and the Linux environment vs the Windows environment.

When the AGW FOIA leak was posted on line I downloaded it and used Kate to open all 1,077 emails at once. Then I could do global searches for key words or phrases. As I clicked through the selected line items in the lower right panel the text of the email would appear in the upper right panel. I could immediately cut & paste selected portions into other documents.

I love Kate!

Comment by moltonel (not verified) (2010-07-27 12:03:00)

Hi, nice blog post and functionality.

I keep watching Kate development because I’d like to one day switch to it. Kate makes regular good progress like this one, but each time I think “great, they finaly have this must-have feature - oh, but $MY_FAV_EDITOR does it better”. Both vim and emacs accomplish your examples with less typing and arguably more ease. There are a few ways to do it in each case although vim’s “/needle/d” and emacs’s “C-x r t > ” stand out as obvious choices.

But perhaps the examples you chose were not ideal. Being too simple (and doable in Kate via other methods, like regexp- replace ?), they fail to show that for a complicated task, javascript might be much easyer to read/type than the equivalent emacs-lisp. Could you show a more complicated example ?

Keep up the good work, I’d still like to switch to Kate someday. But do take the time to properly learn vim or emacs (my champion). Take the (long) time to realize how elegant and usefull their tools are. And steal the good ideas for Kate, while leaving out the kludgy parts.

Comment by Milian Wolff (2010-07-27 13:18:00)

Yeah, I’m aware of the fact that vim and emacs have lots of functionality still not present in Kate. Regarding /needle/d, I hope Erlend will integrate that into his VI-mode for Kate. And I don’t have the time nor interest in learning vim or emacs, Kate simply works for me and I prefer to make it work better than spending my time in other editors and admiring them :P

Regarding more complicated examples… Think of your own that can be implemented using Map-Reduce ;-) I bet others have some idea? I really often use these features only to get something fairly easy up and running…

Bye

Comment by Milian Wolff (2010-08-06 15:59:00)

Got a more advanced example for you:

Assume code like this:

        QList<Parser::TokenType> tokens1;
        tokens1.append(Parser::Token_DOCTYPE);
        tokens1.append(Parser::Token_WHITE);
        ...
        tests.insert("<!doctype root PUBLIC \"uri\" \"uri\">", tokens1);
     
        QList<Parser::TokenType> tokens2;
        tokens2.append(...);
        ...
        tests.insert("bla", tokens2);

Assume you got lots of these blocks and you want to turn that into this:

        {
        QList<Parser::TokenType> tokens;
        tokens.append(Parser::Token_DOCTYPE);
        tokens.append(Parser::Token_WHITE);
        ...
        QTest::newRow("") << "<!doctype root PUBLIC \"uri\" \"uri\">" << tokens;
        }
     
        {
        QList<Parser::TokenType> tokens;
        tokens.append(...);
        ...
        QTest::newRow("") << "bla" << tokens;
        }

All that just by selecting the old code, pressing F7 and running this (complicated) oneliner:

    map 'line.replace(/^\s+(QList|tokens\d+|tests.insert)(.*)$/, function(str, id, rest) { if (id == "QList") { return "    {\n    QList<Parser::TokenType> tokens;"} else if (id == "tests.insert") { return "    QTest::newRow(\"\") << " + rest.replace(/\(|\)/,"").replace(/", tokens\d+\);/, "\" << tokens;\n    }"); } else { return "    tokens" + rest; } })'
Comment by Aaron Seigo (not verified) (2010-07-27 01:51:00)

great stuff; please be sure to document this as thoroughly as possible on techbase. examples in kdeexamples wouldn’t hurt either!

Published on July 27, 2010.