Saturday, July 21, 2007

Extending Kate by Scripts

We have seen how scripting basically works for indentation. It's also possible to register commandline functions (The command line is bound to F7 by default, or invoke View > Switch to Command Line). We will consider a small example again: sort the selected text.
/* kate-script
 * name: unused
 * author: foo bar
 * license: LGPL
 * version: 1
 * kate-version: 3.0
 * functions: sorter
 */

function sorter ()
{
    if (view.hasSelection()) {
        var start = view.startOfSelection().line;
        var end = view.endOfSelection().line;

        var text = document.textRange(start, 0, end, document.lineLength(end));

        var lines = text.split("\n");
        lines.sort();
        text = lines.join("\n");

        view.clearSelection();

        document.editBegin();
        document.removeText(start, 0, end, document.lineLength(end));
        document.insertText(start, 0, text);
        document.editEnd();
    }
}
The header line functions: sorter makes Kate Part aware of the function in the script. A list of functions is supported, separated by white spaces. You can use the function by typing 'sorter' in the commandline.
Some todo items:
  • provide better JavaScript API. For example: document.textRange() takes 4 parameters. It would be more elegant to take one range or two cursors, just like we do in the KTextEditor interfaces in kdelibs/interfaces/ktexteditor
  • make is possible to bind scripts to shortcuts. This could be done by e.g. binding commandline functions to shortcuts or implementing a vim-like command-mode in Kate's commandline. How to configure the shortcuts is unclear, though.
  • then, think about replacing the C++ implementations of 'uppercase', 'lowercase', 'capitalize' etc. with scripts
  • things I forgot...
If you are interested subscribe to kwrite-devel@kde.org and contribute :) We also need indentation scripts, of course!

Friday, July 20, 2007

Kate: More on Indentation Scripting

My last blog was about the theory of how indentation works by using javascripts. Now we will look at a concrete example: a LISP-style indenter. (LISP indentation is easy, that's why it's a good example).
The rules:
  • comments starting with ;;; always have indentation 0
  • comments starting with ;; should be aligned with the next line
  • comments starting with ; should only appear behind code, so they are simply ignored
  • every '(' indents and every ')' unindents
lisp.js looks like this:
/** kate-script
 * name: LISP
 * license: LGPL
 * author: foo bar
 * version: 1
 * kate-version: 3.0
 * type: indentation
 */
// indent should be called when ; is pressed
triggerCharacters = ";";
function indent(line, indentWidth, ch)
{
    // special rules: ;;; -> indent 0
    //                ;;  -> align with next line, if possible
    //                ;   -> usually on the same line as code -> ignore
    textLine = document.line(line);
    if (textLine.search(/^\s*;;;/) != -1) {
        return 0;
    } else if (textLine.search(/^\s*;;/) != -1) {
        // try to align with the next line
        nextLine = document.nextNonEmptyLine(line + 1);
        if (nextLine != -1) {
            return document.firstVirtualColumn(nextLine);
        }
    }

    cursor = document.anchor(line, 0, '(');
    if (cursor) {
        return document.toVirtualColumn(cursor.line, cursor.column) + indentWidth;
    } else {
        return 0;
    }
}

The result:
;;; fib : number -> number
(define (fib n)
  (if (< n 2)
    1
    (+ (fib (- n 1)) (fib (- n 2)))))
As this indenter is scripted, everybody can adapt the style to the own needs.

Wednesday, July 18, 2007

Kate Scripting: Indentation

Kate Part in KDE4 supports the ECMAScript (JavaScript) language by using kjs. In KDE3 we had several hard-coded indenters in C++, the idea is to let scripts do all the indentation in KDE4.
How does it work? It is similar to vim: You simply create a script in the directory $KDEDIR/share/apps/katepart/jscript. An indentation script has to follow several rules:
  1. it must have a valid script header (the first line must include the string kate-script and indentation scripts must have the type: indentation)
  2. it must define some variables and functions
Whenever the user types a character, the flow in Kate Part works like this
  1. check the indentation script's trigger characters, i.e. whether the script wants to indent code for the typed character
  2. if yes, call the indentation function
  3. the return value of the indentation function is an integer value representing the new indentation depth in spaces.
In the 3rd step there are 2 special cases for the return value:
  1. return value = -1: Kate keeps the indentation, that is it searches for the last non-empty line and uses its indentation for the current line
  2. return value < -1 tells Kate to do nothing
So how does a script look like exactly?
The name does not really matter, so let's call it foobar.js:
/* kate-script
* name: MyLanguage Indenter
* license: LGPL
* author: Foo Bar
* version: 1
* kate-version: 3.0
* type: indentation
*
* optional bla bla here
*/

// specifies the characters which should trigger indent() beside the default '\n'
triggerCharacters = "{}";

// called for the triggerCharacters {} and
function indent(line, indentWidth, typedChar)
{
// do calculations here
// if typedChar is an empty string, the user hit enter/return

// todo: Implement your indentation algorithms here.
return -1; // keep indentation
}
More details on the header:
  • name [required]: the name will appear in Kate's menus
  • license [optional]: not visible in gui, but should be specified in js-files. it is always better to have a defined license
  • author [optional]: name
  • version [optional]: recommended. an integer
  • kate-version [required]: the minimum required kate-version (e.g. for api changes)
  • type [required]: must be set to indentation
The only missing part is the API which Kate Part exports to access the document and the view. Right now, there is no API documentation, so you have to look at the code:
You will find, that the current document exports functions like
  • document.fileName()
  • document.isModified()
  • document.charAt(line, column)
  • etc...
The view exports functions like
  • view.cursorPosition()
  • view.hasSelection()
  • view.clearSelection()
  • ...
That's the boring part of this blog. The interesting one is unfortunately shorter: we are looking for contributors who want to write scripts or help in the C++ implementation :)

Saturday, July 14, 2007

Luggage continued

Quick notice: I have my bag back. It was wet inside -- probably for 2 weeks, no wonder it started to get moldy inside, and I'm not sure yet whether I can use some of the clothes. Well done BA & Heathrow.

Wednesday, July 11, 2007

Deeply impressed...

Hey, I wasn't aware there was another one who did not get his luggage at all in Glasgow. I traveled from Frankfurt(Germany) to London (Heathrow) and then on to Glasgow. When I arrived, my luggage was missing. British Airways told me it would still be in London but it should arrive the same day and they would bring it to the Euro Hostel - cool :) How naive! Of course it did not arrive... and it didn't arrive the whole week.
The online status always said "Still tracing, check back later". When I flew back I asked at the Glasgow airport again and was told they can not see more than what I see online. When I asked whether they could call London/Heathrow by phone they said in London/Heathrow 20.000 bags are missing so it would be pointless. If the system is so unreliable, why don't they simply close the airport. moo
When I arrived in London I asked again, and a BA-service guy told me he could see that my luggage was being sent to Glasgow by road. By road??? Hell, it takes them 1 hour by plane, so what? And I even told them that I would leave this day. So why to Glasgow at all now?
Well, finally I sat in the plane... which ironically had a delay because it had one bag too much. Hey, that could have been mine... :)
Back in Frankfurt I asked again, and at least this time they were capable of changing the destination address to where I live in Germany. Strange, I told them in Glasgow in the first place, but they seem to be pretty much incapable... :)
So here we go: Back in Germany... in the meanwhile I wondered whether I'd see my bag ever again. Today, almost 2 weeks later, the state incredibly changed to "Received at the airport, delivery in progress". Wow, I'm deeply impressed... really great job. Wait: at which airport? Glasgow? London? Frankfurt? Or somewhere else in the world? *sigh*
So in short: I still don't have my luggage back... :)