ReindentCodeLog - robmcmullen/peppy GitHub Wiki

Table of Contents

Notes on the Development of the C-Style Reindent

This is a journal of my development of the python code that is used to reindent C-style modes.

Problem

Need to have a way to determine the correct indent level of a line in C/C++/Java style modes. This is bug #308 in the ticket tracker.

Background

I did a lot of searching to see if there was a python implementation of this problem. I couldn't find any, so unfortunately I have to implement it by hand. I found some implementations in other languages:

I'm going to do this in at least two steps: a regex based system, then a full-blown C-style system. The regex based system will be much easier, and since the source code for kate is under the LGPL and it looks relatively straight-forward, that's some low-hanging fruit.

Regex Autoindent

I'm going to start from as brain-dead thing as I possibly can: a literal translation of the kate's KateVarIndent class from kateautoindent.cpp. My python code can be found in autoindent.py in whatever state it is currently.

The first version is a translation of the KateVarIndent::processLine into the python method getReindentColumn in the RegexAutoindent class. getReindentColumn differs slightly from processLine in that it returns the column number to which the line should be indented, rather than actually reindenting the line as processLine does. Another difference is that I've not handled the processChar option -- Kate's character event handling routine must call the processChar method for every char press.

(This is an appealing idea; to provide an autoindenter for every FundamentalMode instance and have the major mode and action be outside the scope of knowing when a line is indented. I may investigate that further.)

I added a simple bash mode as an example of the autoindent at work. Hitting tab reindents the line to an appropriate level. I haven't gotten it to work for the return character yet -- hitting return should indent the line to the right spot and put the correct amount of indentation at the following line.

Using Scintilla's Folding for Autoindent

Scintilla (the C++ component that makes up the wx.stc.StyledTextCtrl) has a built-in parser for source code that provides code folding.

Python Folding

I experimented with it for python autoindenting, but it wouldn't work because for python mode the folding logic simply reports the current level of indentation as the correct level. With python it's not always possible to determine what the indentation level should be. Look at the nested if statements below: to which clause does the else belong, and how is Scintilla's lexer going to make that determination? It's unsurprising that Scintilla's logic just punts and says "the existing indentation must be what the user intended."

#!python
def blah:
    if True:
        stuff
        if False:
            other stuff
      else:
For python mode, I found the IDLE reindenting stuff and all is well. (Er, mostly. See #403)

C-style Folding

However, for C-style modes, folding looks to be much more useful. In these modes, scintilla can report the correct folding depth because it can count braces! Using the generic FoldingAutoindent class, reindenting the else statement below:

#!c
void blah(int stuff) {
    if (1) {
        printf("True");
        }
else {
correctly indents it to column 4:
#!c
void blah(int stuff) {
    if (1) {
        printf("True");
        }
    else {
Note the closing braces are indented to the same level as the rest of the block, so some heuristics will have to be added to a custom subclass of FoldingAutoindent, but I think that this could be workable.

This autoindenter lives in peppy/lib/autoindent.py.

  • r1168 is the first revision of the code that includes C-style indenting. The class has only the very basic functionality. It indents to the level of the braces, but do anything fancy like line up arguments when an unmatched open paren is found.
  • r1169 added a simple check for #define statements (actually, all preprocessor directives) that ignores them in terms of autoindenting.
  • r1170 added reindenting and newlines on semicolon and open/close brace. (Note: there are probably some people who don't like this, so it should be made an option instead of always being on.)

Scintilla Won't Fold the Last Line

I don't know if this is a bug or a feature, but Scintilla always reports a fold level of zero for the last line in the file. If you really want to indent that line, you have to add a return character and then try to indent it again. This comes into play when typing in a blank file and expecting the folding to work.

Augmenting C Indentation with Regexes

As of r1170, the folding provided by Scintilla's provides a first cut at the automatic indentation. However, it fails to indent multi-line continuation statements like:

   do_something(arg1, arg2,
   arg3);
or code like:
    if (stuff)
    printf("Stuff!\
");
A simple way to handle this is to indent any line where the previous line doesn't end in a semicolon. This takes care of the if statement:
    if (stuff)
       printf("Stuff!\
");
bit doesn't align arguments of function calls:
   do_something(arg1, arg2,
       arg3);
⚠️ **GitHub.com Fallback** ⚠️