The Variable Based Indenter

This article was originally published as a blog at http://www.alweb.dk/blog/anders/autoindentation at 2004/11/02.

NOTE Mon Nov 1 16:49:03 CET 2004: revised versions of the variables for both perl and bash. Also update kdelibs/kate/part.

Some time ago, when I convinced Laurence Withers to contribute a XML auto-indenter to Kate, I got the idea that we should also have a more flexible indenter that could be configured using the document variable system. The other day while commenting on this bug I was reminded again. So in one of my usual streaks away from my overfilled TODO list, I sat down and implemented one last night..

The commit log in a friendly formatting looks like this:

Add a variable based autoindenter.

This indenter matches a line and the first line with content above against
regular expressions to decide if a line should be [un]indented. When a newline
is entered, both the old and the new line is considered, and it can be triggered
to indent the current by typing one of a list of characters.

The regular expression patterns and trigger character list are read from document variables, which can be embedded directly in the document or read from a filetype configuration.

The following variables are used:
var-indent-indent-after
a regular expression pattern, if the first line with content above the current, indentation is added
var-indent-indent
a regular expression pattern, if the current line matches indent is added. this is not tested if the above matched.
var-indent-unindent
a regular expression pattern, if it matches the current line, indent is removed.
var-indent-triggerchars
a string of characters, when any is typed, the current line is reindented.

This should be usable for adding basic autoindentation to bash, lua, basic, perl...
Note that Kate's document variables currently can't contain a semicolon, (would be a common trigger char), I'm going to fix that.

How to use it

I'd really appreciate it if some of you would like help me testing this! If you run cvs HEAD and write bash or perl code, please consider using the configurations below, and let me know how it works out. If you want to define variables for another language, don't hesitate to come into #kate at irc.freenode.net and ask me for help.

The general idea is to store the variables needed to define indentation for language X in a filetype configuration, but the variables can of cause be stored in any location from where kate will read them. So far, I have defined variables that seems to work with bash script and with perl. It looks like this:

Variables required to autoindent bash script:

# kate: indent-mode varindent;
# kate: var-indent-indent-after (\{(?![^\}]*\})|\b(then|elif|else)\b(?!.+fi)|\\bdo\b(?!.+done)|\bcase\s+.+\s+in\b(?!.*esac)|\[\[);
# kate: var-indent-indent \$\{.*\};
# kate: var-indent-unindent ([}]\s*$|\b(fi|elif|else)\b|\bdone\b|\besac\b|\]\]);
# kate: var-indent-triggerchars {};

The entry from ~/.kde/share/config/katefiletyperc looks like this (NOTE that the Variables property has been broken into several lines, the continued lines are indented. The double backslashes seems to be a KConfig thing.):

[Bash]
Mimetypes=application/x-shellscript
Section=Scripts
Variables=kate: indent-mode varindent;
  var-indent-indent-after (\\{(?![^\\}]*\\})|\b(then|elif|else)\b(?!.+fi)\\bdo\b(?!.+done)|\\bcase\\s+\\s+in\\b(?!.*esac)|\\[\\[);
  var-indent-indent \\$\\{.*\\};
  var-indent-unindent (\\}|\\b(fi|elif|else)\\b|\\bdone\b|\\besac\\b|\\]\\]);
  var-indent-triggerchars {};
Wildcards=*.sh

Explanation:

  1. The var-indent-indent-after variable matches any line that looks like an unfinished bash control loop, or like it has an opening curly brace or a double square bracket opening.
  2. The var-indent-unindent variable matches any of the corresponding closing elements.
  3. The var-indent-indent variable adds indentation if the line has variables enclosed in curly braces, in anticipation of the unindenter removing it again. This might seem a bit silly, but so far I haven't a better solution.
  4. Finally, the var-indent-triggerchars variable causes immediate indentation when a curly brace is entered. (the textual closings will be unindented when/if a newline is entered.)

Variables required to autoindent perl code:

(hey, who'd have thought that those would be simpler?)

# kate: indent-mode varindent;
# kate: var-indent-indent-after (?:\{(?![^}]*\})|\((?![^\)]*\)));
# kate: var-indent-indent (?:\{.*\}|\(.*\));
# kate: var-indent-unindent [})];
# kate: var-indent-triggerchars });

... and the corresponding filetyperc entry:

[Perl]
Mimetypes=text/x-perl
Section=Scripts
Variables=kate: indent-mode varindent;
  var-indent-indent-after (?:\\{(?![^}]*\\})|\\((?![^\)]*\\)));
  var-indent-indent (?:\\{.*\\}|\\(.*\\));
  var-indent-unindent [})];
  var-indent-triggerchars });
Wildcards=*.pl;*.pm

This works much like the bash configuration, but simpler, since all i care for is indenting [curly brace] blocks and multiline parens. For perl, a semicolon shoudl really cause reindenting, but kate can't read that from a variable yet :-\

...uhm.. I'm going to have to create a working configuration for CSS ASAP!

Comments

how to enter this info?

I’m curious on a new editor for perl and Kate looks very appealing with the file tabs and shell at the bottom etc

Forgive my ignorance, but how do I set up the Perl stuff above for my Kate? I see there’s 2 sections.

where do I put in:

# kate: indent-mode varindent;
# kate: var-indent-indent-after (?:\{(?![^}]*\})|\((?![^\)]*\)));
# kate: var-indent-indent (?:\{.*\}|\(.*\));
# kate: var-indent-unindent [})];
# kate: var-indent-triggerchars });

I see there’s a “configure” button next to the dropdown menu for autoindent method in the configuration, but it’s greyed out…

About the corresponding file entry: The ~/.kde/share/config/katefiletyperc is non existant on my KDE 3.5.6 kubuntu system. Will just putting the stuff quoted in the article into a fresh file with that name work?

Cheers!

an idea

why not include the variables for this feature also in the XML highlighting settings, would be much more nice than the config imho.

Perl indenting in Kate 2.5.2

For Kate 2.5.2 (KDE 3.5.2) in Ubuntu 6.06.1 (under Gnome) the following gets basic curly braces and parentheses indent matching working.

[Perl] Mimetypes=text/x-perl Priority=1 Section=Scripts Variables=kate: indent-mode varindent; var-indent-indent-after ((\{(?![^}]\}))|((][)])));; var-indent-indent (\{.\}|\(.\)); var-indent-unindent [})]; var-indent-triggerchars }); Wildcards=.pl;.pm;

What is ?: - it's not listed in the regexp section of the book

What is ?: - it’s not listed in the regexp section of the Kate Handbook. Is it a new assertion? (?:… doesn’t mean anything to me, based on the regexps in the handbook.

Bug: if the first line in

Bug: if the first line in the file matches var-indent-indent-after, then this first line gets indented (regardless of a match to var-indent-indent).

Matlab Section

Here are the beginnings of a matlab block:

[Matlab]
Mimetypes=text/x-matlab
Section=Scientific
Variables=kate: indent-mode varindent; var-indent-indent-after ^( )*(for|else|if|while|switch|function); var-indent-unindent (end)
Wildcards=*.m

Starting a matlab section

Here’s the beginnings of a section for matlab code:

[Matlab]
Section=Scientific
Variables=kate: indent-mode varindent; var-indent-indent-after ^( )*(for|else|if|while|switch|function); var-indent-unindent (end)
Wildcards=*.m

Here's a Ruby section for

Here’s a Ruby section for .kde/share/config/katefiletyperc. Please note that there’s just one Variables line and that you have to create the file if it doesn’t exist.

[Ruby]
Mimetypes=application/x-ruby
Section=Scripts
Variables=kate: indent-mode varindent; var-indent-indent-after ^( )*(if|while|def|class|for).*|\\{[^\\}]*$|else|elsif|rescue|do|begin; var-indent-indent; var-indent-unindent end|else|elsif|rescue|^[^\\{]*\\}; var-indent-triggerchars }def; space-indent on; indent-width 2;
Wildcards=*.rb

By Juan Ignacio Pumarino R. // jipumarino at gmail.com

Slightly different

I’m using a slightly modified version of your section:

[Ruby]
Mimetypes=application/x-ruby
Section=Scripts
Variables=kate: indent-mode varindent; var-indent-indent-after ^( )*(if|while|def|class|for|unless).*|\\{[^\\}]*$|else|elsif|rescue|do|begin; var-indent-indent; var-indent-unindent ^( )*(end|else|elsif|rescue)|^[^\\{]*\\}; var-indent-triggerchars }def; space-indent on; indent-width 2;
Wildcards=*.rb

There’s mostly support for “unless” blocks and a slightly refined match for ending a block. Otherwise, e.g. “render” would match the unindent expression. It’s still necessary to have it match only full tokens, since e.g.

begin
  endowment

has “endowment” match unindent (it starts with “end”) and thus unintents the second line. I’m not quite sure what kind of regular expressions is used by kate, and also the unindentation triggers while you type, so there’s probably no way around it. (It would have to unindent after “end”, and then reindent once the token doesn’t match anymore.)

Otherwise, it works pretty well, but creates a spurious indentation level if you’re starting a block on the first line in the file. As long as the first line doesn’t match the indent-after expression, it’s fine. My personal guess is that this is due to a bug in kate.

doesn't work for me

the perl settings work fine - but these Ruby settings do not. any suggestions?

Post new comment

  • You can use Markdown syntax to format and style the text.
  • You may link to images on this site using a special syntax
  • Web page addresses and e-mail addresses turn into links automatically.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Image CAPTCHA
Copy the characters (respecting upper/lower case) from the image.