RFC: Exporting JavaScript API

Since quite some time, Kate Part has build-in scripting support through JavaScript. Our plan is to make this API public, so other applications like Kile, Kate App and KDevelop can use it. However, we are currently unsure how to best implement it, so this is a rfc to get feedback.

The bindings for a Kate Document are for instance located in part/script/katescriptdocument.h (header, implementation). As you can see, there are functions like

Q_INVOKABLE bool insertLine(int line, const QString &s),

which can be invoked in our scripting by a call of ‘document.insertLine(5, “hello world”)’. The API only contains basic functions. But for instance Kile maybe also wants to provide a function called ‘document.insertSection()’ or similar LaTeX related functions. The question now is as follows: How can Kile extend our QObject based prototype with their own QObject based classes?

We do not want to make the class KateScriptDocument public. Instead, we just want to return a QScriptValue containing a QObject based KateScriptDocument. You can think of the problem also as follows:

// in Kile:
QScriptEngine *engine = ...;
KTextEditor::Document *kteDocument = ...;

QObject* kateScriptDocument = kteDocument->scriptDocument();
engine->globalObject().setProperty("document", engine->newQObject(kateScriptDocument));
// at this point, the JavaScript object 'document' contains all KateScriptDocument functions

// next, we want to add the Kile related document functions
KileTextDocument* kileDocument = ...;
QObject* kileScriptDocument = kileDocument->...(); // some function that returns the binginds object

// now: how can we populate the 'document' property with the functions in kileScriptDocument?
engine->globalObject().setProperty("document", ? );

If you have any idea or other solutions how to do it right, please let us know!

Crash through D-Bus calls

Years ago, there was a blog on the planet with the title “How to crash (almost) every Qt/KDE Application and how to fix it“. In short, if you are showing a dialog, KWin prevents you from closing the application by clicking on the close button in the window decoration. However, through D-Bus, you can still quit the application. A solution was also provided: Use a guarded pointer to create the dialog.While this fixes the issue, it looks like fixing the blame, and not the real issue. Stricktly speaking, even the Qt documentation would be wrong then.

Searching for ‘Accepted’ on lxr.kde.org shows lots of dialogs that lead to possible crashes. I wonder whether developers are really aware of this crash? Even if we took care of this issue as proposed, it’s just a matter of time until dialogs are created the `wrong’ way again (do we have krazy checks for that?). In Kate, no one took care of this situation, meaning that you can indeed crash the application through D-Bus.

Is there a better way to fix this?

On Removing an Element from a List

Recently, there was a very good blog about The Importance of Mentoring. It was mentioned that the 3200 slocs of the gsoc projects could be cut down to 500 slocs, doing exactly the same thing.

While hunting some crashes in the new code folding code from the last gsoc project, I obviously had a closer look on how things are implemented. The code folding uses a simple tree structure. Nodes can be added, removed or moved around. So I stumbled over the following code:

01 // removes it from children list (QVector)
02 bool SomeClass::removeItem(Item* it)
03 {
04   bool found = false;
05   int i;
06
07   for (i = 0 ; i < children.size(); ++i) {
08     if (children[i] == it) {
09       found = true;
10       break;
11     }
12   }
13
14   if (found) {
15     children.remove(i);
16     return true;
17   }
18
19   return false;
20 }

This code appears several times in different locations. It can easily be rewritten as

01 // removes it from children list (QVector)
02 bool SomeClass::removeItem(Item* it)
03 {
04   int i = children.indexOf(it);
05   if (i != -1) {
06     children.remove(i);
07   }
08
09   return i != -1;
10 }

So without much work, the code is reduced to the half. Diving further into the code, I stumbled over a class KateDocumentPosition. This class is a line/column tuple representing a position in the document. It features operators like <, >, for convenience. Now you may guess it: Kate Part is a text editor using “document positions”all over the place, e.g. for the cursor, the text selection, bracket matching, search & replace and what not. In fact, there is no way around using line/column tuples as position markers. Thus, it should not be surprising that we have a public class called KTextEditor::Cursor, featuring everything what KateDocumentPosition implements (and more). The Cursor class is basically used everywhere, and it works as expected (our unit test rely on it, too). There is no need to duplicate the code. This probably happened because the student was not aware of it.

Martin writes “Be prepared for the worst“. Well, true. In this case, the project was successful and the new code folding works better than the old one (after fixing the crashes). Now if you are a gsoc student reading this blog, don’t feel discouraged. Rather feel encouraged to communicate with the developers a lot, e.g. by discussions on the mailing list :-)

Append Newline at End of File

In KDE SC 4.9, Kate Part will have an option in the Open/Save config tab called

[ ] Append newline at end of file on save

By default (and Kate tradition), this option is off. You can also use the document variable (modeline) newline-at-eof [bool], either in the file itself, in a .kateconfig file, or in the “Modes & Filetypes” config page. If a newline was added, it is visible only after reloading the document. This finally fixes wish #256134.