Kate linter plugin

Just a quicky: I wrote a little plugin for KTextEditor which supplies you with basic error checking when you save documents. Currently only PHP (via php -l) and JavaScript (via JavaScript Lint) are supported.

Screenshots
Requirements
  • usual tools for compiling C++, e.g. gcc.
  • cmake
  • Qt development packages, i.e. under Ubuntu: sudo aptitude install libqt4-dev
  • KDE 4.2 with development packages for kdelibs and kdebase, i.e. under Ubuntu: sudo aptitude install kdebase-dev kdebase-workspace-dev kdelibs5-dev. Note: You’ll need the experimental KDE 4.2 packages activated as of now, see for example the Kubuntu news on KDE 4.2 RC1 for hints.
  • proper setup of environment variables, read this techbase article for more information. the .bashrc linked there should be enough for most people
  • For PHP support: a PHP executable which supports the -l switch for linting
  • For JavaScript support: a JavaScript Lint executable, you could download and compile the sources for example.
Installing

Get the sources for the linter plugin from KDE SVN and compile it, using e.g. the functions supplied via the .bashrc mentioned above:

  1. # go to your development folder
  2. cs
  3. # checkout sources
  4. svn co svn://anonsvn.kde.org/home/kde/trunk/playground/devtools/kte_linter
  5. cd kte_linter
  6. # build base linter plugin
  7. cd linter
  8. cmakekde
  9. # build php linter plugin
  10. cd ../phplinter
  11. cmakekde
  12. # build javascript linter plugin
  13. cd ../jslinter
  14. cmakekde
  15. # update sycoca
  16. kbuildsycoca4
  17. # start editor and select the plugins - happy coding!
  18. kwrite
Todo
  • Support for more languages

    If you know good linters drop me a note. But it would be even better if you could write your own linter plugin. It’s pretty easy, take a look at one of the existing plugins for a skeleton & documentation.

  • Right now each plugin returns a hardcoded list of highlighting-modes which it supports for linting. This should be made configurable so that custom highlighting modes are supported

  • make error messages more pretty

Happy coding!

System Load Viewer

Last year I’ve blogged about the missing system monitor with the three bars for the panel and about its port to Plasma. Meanwhile other developers also did a port called System Status. In a collaboration with them we finally have the applet back in KDE’s subversion, the name is now “System Load Viewer” and it uses the data engine “systemmonitor” that already exists in KDE 4.2.
So if you want to have the plasmoid for your KDE4.2 desktop, it should be straightforward to compile/install.
On the screenshot you can see the plasmoid in action. There are two instances, one on the panel and one on the desktop. The one on the left is the KDE3 one.

It’s worth to mention that the plasmoid already supports more featues than the KDE3 version. Features include:

  • show all cpus (for computers with multicores)
  • tooltip updates continuously
  • nicer visualization (maybe needs some more tweaks)

As soon as the KDE 4.2 freeze is over we’ll have to see where we can put the plasmoid to make sure it’s available for KDE 4.3 :)

Kate Internals: The Undo/Redo System

The Kate Editor Component (also called KatePart) has its own undo/redo system. It did not change much since KDE2 and basically it is very simple. Meanwhile there are classes for undo/redo support in Qt as well. In fact both systems are very similar. This article focuses on Kate Part’s system.

Text Operations

First we have to take a look at what actions need to be saved. In Kate Part this basically comes down to

  • insert text or line
  • remove text or line
  • selection changes
  • (and a few others like wrapping a line)

When typing text, each keystroke inserts a character. This is exactly one undo/redo item. As example, typing a character ‘x’ creates a new undo item:

  • the content is ‘x’
  • the type is ‘insert text

Undo in this case means ‘remove x‘. Redo means ‘insert x (again)‘. Hence, the undo/redo history is just a list (more like a stack to be precise) of simple edit actions.

KateUndo Items

In KatePart, each edit primitive in the undo history is based on the class KateUndo:

class KateUndo {
public:
  KateUndo(KateDocument* document);
  virtual ~KateUndo();

  enum UndoType {
    editInsertText,
    editRemoveText,
    editWrapLine,
    editUnWrapLine,
    editInsertLine,
    editRemoveLine,
    editMarkLineAutoWrapped,
    editInvalid
  }; 

  virtual bool mergeWith(const KateUndo* undo);

  virtual void undo() = 0;
  virtual void redo() = 0;

  virtual KateUndo::UndoType type() const = 0;
};

For each of the edit primitives above exists a subclass of KateUndo, for instance the class for inserting text looks like this:

class KateEditInsertTextUndo : public KateUndo
{
  public:
    KateEditInsertTextUndo (KateDocument *document,
                            int line, int col, const QString &text);

    virtual void undo();
    virtual void redo();

    bool mergeWith (const KateUndo *undo);

    KateUndo::UndoType type() const { return KateUndo::editInsertText; }

  private:
    const int m_line;
    const int m_col;
    QString m_text;
};

Item Merging

Note the function KateUndo::mergeWith(const KateUndo* undo); This functions merges two undo items of the same type if possible. For instance, typing ‘hello world’ inserts one undo item for every character, i.e. 11 undo items of type ‘insert text’. Kate merges those 11 items into only 1 item with the string ‘hello world’. Merging leads to less KateUndo items (less memory) and faster undo/redo replaying.

Item Grouping

What’s still missing is the possibility to group several undo items together. Imagine you have selected the text ‘hello world’ and paste the text ‘cheers’ from the clipboard. What happens is this

  1. remove selected text
  2. insert text from clipboard

So there are two undo items of different type. They cannot be merged into only one KateUndo item. Though, we want to support undoing both items in one go, that’s why we add several undo items into undo groups. In KatePart, this is done by the class KateUndoGroup:

class KateUndoGroup {
public:
  explicit KateUndoGroup (KateUndoManager *manager,
                          const KTextEditor::Cursor &cursorPosition,
                          const KTextEditor::Range &selectionRange);

  void undo(KTextEditor::View *view);
  void redo(KTextEditor::View *view);

  enum UndoType { ... };

  void addItem (KateUndoGroup::UndoType type, uint line,
                uint col, uint len, const QString &text);
  void setUndoSelection (const KTextEditor::Range &selection);
  void setRedoSelection (const KTextEditor::Range &selection);
  void setUndoCursor(const KTextEditor::Cursor &cursor);
  void setRedoCursor(const KTextEditor::Cursor &cursor);
  bool merge(KateUndoGroup* newGroup,bool complex);
  void safePoint (bool safePoint=true);
};

Every KateUndo item belongs to one KateUndoGroup. A KateUndoGroup can have an arbitrary count of KateUndo items. In the example above we want to group ‘remove selected text‘ and ‘insert text‘ together. Grouping can be explicitely done in the code as follows (simplified version):

void KateDocument::paste( KateView* view, QClipboard::Mode mode )
{
  QString s = QApplication::clipboard()->text(mode);
  editStart();
  view->removeSelectedText();
  insertText(pos, s, view->blockSelectionMode());
  editEnd();
}

Grouping: editStart()/editEnd()

The call of editStart() tells the document that an edit operation is running. All text operations are added to the current KateUndoGroup, until editEnd() is called. editStart() and editEnd() do reference counting, i.e. editStart() can be called nested as long as for each call of editStart() there is (finally) a call of editEnd().

Grouping: Cursors and Selections

Undoing the paste-action above should restore the selection if there was one previously. Redo (i.e. paste again) should remove the selection again. So there are two different types of selections: one before the undo group, and one after. That’s why each undo group has the functions setUndoSelection() and setRedoSelection(). The same applies for the cursor position: We have to store two different cursor positions, one for undo and one for redo.
For instance, imagine we removed the text ‘world’. Undo (i.e. insert ‘hello‘) should set the cursor position to the end of ‘hello’. Redo (i.e. remove ‘hello‘) should set the cursor position to the start of it.

Luckily a programmer does not have to set the undo/redo cursor positions and text selections manually. undoStart() is called the first time editStart() is called. The closing editEnd() finally calls undoEnd(). So undoStart() sets the undo cursor position and undo text selection, while undoEnd() sets the redo cursor position and redo text selection.

Group Merging

The careful reader might have noticed KateUndoGroup::merge(). So merging of two groups is also supported. Whether text operations should be merged into an existing undo group can be controlled with KateDocument::setUndoDontMerge(). Pasting text for example set’s this flag.

Undo and Redo

Every document in KatePart has two lists: An undo list, and a redo list. Suppose we have 10 KateUndoGroups in the undo list and the user invokes undo 4 times. Then the undo list only contains 6 items and the redo list 4. Now it is also possible to redo. However, typing text clears the redo list.

Document Modified Flag

KateDocument::updateModifed() is called to update the modified flag of a file. This update also relies on the current active undo group. Saving the file saves a pointer to the current undo group, and later we simply can check whether the current undo group is the active one. Pretty simple mechanism.

Akademy 08: Kate Flashback

This Akademy’s Kate changes include

  • fix: drag & drop of text
  • code completion: only show group header if the group name is not empty
  • reintroduction of buffer blocks in Kate’s document buffer (one buffer contains up to 4096 lines). The blocks build a linked list. Editing a 500 MB file kind of works now again. It’s still rather slow, though.
  • more speedup in Kate’s document buffer
  • Kate is using KEncodingProber instead of KEncodingDetector now
  • generate internal version of KatePart automatically, so developers don’t have to adapt it manually each release
  • python encoding detection plugin that warns if encoding is not correct while saving
  • new plugin: Backtrace browser, mainly for developers
  • find in files: several speed optimizations
  • find in files: progress indicator while search is active
  • find in files: redesign of workflow. Search happens with non-modal dialog and results are shown in toolviews.
  • lots of vi mode changes
  • lots of bugs closed, mainly old ones
  • some real bug fixes…
  • things I forgot