[ANN] Tabifier version 4.3

The tabifier plugin retabs Java code so that syntactic elements are aligned vertically.

Version 4.3 handles array initializers better, and provides an option to disable array initializer formatting completely.

Version 4.3 also fixes a problem with class-level comments, which were being aligned with field declaration trailing comments. Any comment in a class (or after the class, e.g. after the closing right brace) which has no preceding text or which occurs before any declarations are seen, is considered a class-level comment and will be left justified.

Download with plugin manager or at http://www.intellij.org/twiki/bin/view/Main/TabifierPlugin. (There's no difference between version 4.2 and 4.3 except for the Plugin Manager change text, so get version 4.2 at the wiki site.)

As always, please let me know of any problems.


Comment actions Permalink

off the top of my head

Could you assign, to each line in a block, the number of spaces that it was responsible for creating in the other lines. Then separate it if any line is above the max_value threshold. If that line is closer to the top of the block, split below the line. If it is closer to the bottom, split above the line.

Then redo the procedure with the 2 sub-blocks until no line is above the max_value.

Comment actions Permalink

I'm not sure I follow you. How exactly do I calculate the number of spaces a line creates in (all) other lines?
For example, given

does "String s" cause "int i" to have 3 extra spaces, but Stringbuffer cause "int i" to have an additional 6? Or are all 9 assigned to the last line?

It would be much easier to calculate the number of "extra" spaces inserted in a given line than to determine the effect of other lines on a given line. Could your algorithm be retuned to use those numbers somehow?

It would be great if you could supply an example with enough lines to show how what you are describing would work, with the calculations you've got in mind.

Off for the weekend, talk to you Monday - :)

Comment actions Permalink

sorry 'bout the late reply. I was away at the weekend also.

Things do indeed get complicated in order to acheive what I was envisioning...

Here's my new (semi complex) idea. This explanation only applies to spaces before the assignment operator. You may need to repeat this rule for spaces after the assignment operator and for aligned parameters within methods also.

Each line holds 2 values...

The number of spaces that has been added to it.
The number of spaces that would be saved if the block were split directly below itself...

In the example below, I would say that

1st line: 9 spaces added, 3 saved if split below.
2nd Line: 6 spaces added, 15 saved if split below.
3rd line: 0 spaces added, 3 saved if split below.
4th Line: 3 spaces added, 0 saved if split below.

In most cases, I don't think people care about a lot of spaces in an alignment block so they might set their max value to be, say, 30. In this case nothing would happen in the above example and all is well. However, if the programmer were more finickity about spaces then they might set the max-value to be 5, in which case both line 1 and line 2 would violate the max spaces rule and the block would be split.

In the splitting, the line would be split below line 2 and the max_value constraint would be satisfied.

Things get a little stickier if you want to consider other aspects of the line separately (as you might). After the assignment operator there's an identical but separate issue.


In the above case the values would be (before the assignment)

1st line: 13 spaces added, 13 saved if split below.
2nd line: 0 spaces added, 12 saved if split below.
3rd line: 13 spaces added, 6 saved if split below.
4th line: 6 spaces added, 0 saved if split below.

However, when looking at the lines after the operator, we see that we can save the most spaces if we set the split after line 1 or line 2 we save 6 spaces (because we right justified integers). And we have the following numbers for each line.

so with MAX_VALUE_BEFORE_OPERATOR = 10 and MAX_VALUE_AFTER_OPERATOR = 10 we would have to split the group. We would therefore choose the maximum savings which would be to split after the first line.

We would then have

for the last 3 lines we would now have...

And we would split after the 2nd line and repeat and then split after the 3rd line too (leaving no tabification on this block if the max_values were set to 10).

The idea being that we would keep splitting at the point that would save the most spaces as long as there are more spaces than is acceptable on any line in the block.

Not trivial, but it's the best algorithm I can think of for acheiving what we're talking about.

A simpler (and less comprehensive) solution in the above example would be to have integers only right justify with other integers rather than other varable names and strings and such.

what do you think?

Comment actions Permalink

Hi Joe,

I think I generally understand what you're trying to achieve. One thing I can certainly do is align right-justified integers separately from other terms. I have been noticing this for a while.

I have some questions about how you determined your "second value" (number of spaces saved if block were split).

In the example

I understand your "spaces added" figures but not how you obtain the second value. Is this second value supposed to be the number of spaces saved in the next subblock if a new subblock began immediately after the line we're considering? No matter, I can't figure out how you are calculating it.

If we break the group after the first line, we'd get

I don't see where you save 3 spaces.

If we break the group after the second line we'd get:

You came up with 15 spaces saved here, but I only count 12.

In your second example,

you have right-aligned the variable names. This isn't something the tabifier does right now but probably could with some work. If you left-align everything as is done today, you start with

Here the right-aligned variable names saves you some space because the long "aLongString" combines with a shorter variable type "String" so 3 spaces are saved on each line just in the combination of variable type and name.

So, 3 items:
1) I'll add an option to right justify literals only with respect to other right-justified literals. That prevents the "10" from sliding right so far in the last example above.
2) Please explain your algorithm for obtaining the second metric.
3) Is the ability to right-justify variable names desirable?


Comment actions Permalink

Ha! Fair points all.

I realized that I'd made a mistake on my space counting example after I'd sent it to you. I hadn't noticed I'd made 2 errors. You are right on both counts of course. You'd save 8 and then 12 spaces.

You were also right about the justification of the variable names. That serves me right for not taking my example out of my code rather than just making one up (with errors). Personally, I have no desire for right justified variables.

So, in the above example, 9 spaces would be saved splitting the block after line 3 (3 spaces each on the first 3 lines), and 30 would be saved splitting after line 2. 3 each on the first 2 lines and 9 each on the second 2. And, after the operator, 6 spaces on line 3.

The other question is whether you might want MAX_VALUES for all the sub-groups of justifications (types, variable names, assignments). Personally I would, because the concept of what we're trying to do is clear to me. I couldn't speak to whether it might be more confusing to casual users.

As an aside, one other thing I'd love to see in the IDE tabifier settings tab, is a code example for every checkable box. Many of the options do not affect the example code in the right-hand window and the only way I can see what the effect will be is to select it and try it on my code.

Comment actions Permalink

Good, I thought I was going crazy. (My chess instructor is all over me for not being able to count. I told him that there are three kinds of people; those who can do math, and those who can't. :)

Yeah, the preview pain. I mean, pane. I thought about putting more stuff in it, but it seems to just get longer and longer. Starts to look like my collection of Junit tests!

What if you could see a copy of your own current file in the preview pane? Then you'd be able to tell exactly what effect the settings would have on some code that meant something to you. (For a very long file, it could take a long time, of course. OK, an option to do it or not.) Maybe I could even scroll to your current location.

I'd have to investigate how to do it.


Comment actions Permalink

What's your opinion on how best to implement the spaces limitation concept (or whether it should be done at all)?

Should I start counting the days to tabifier 5.0? ;)

And, as I've always said... There are 2 kinds of people in the world; people who split people into 2 kinds of people and people who don't.

Comment actions Permalink


Another feature request... Could you separate alignment of parameters in method signatures from alignment of parameters in method calls.

I love having the parameter names aligned in the signature line but I'd like to avoid the following...

Comment actions Permalink

I want to do some experimentation to see if a single per-line threshold yields decent (significantly improved) results. I have a feeling that if we implemented per-field thresholds, (a) it would be very confusing to people (especially me, who has to implement it!) and (b) it might be hard to implement if the thresholds could be contradictory. I.e. are there situations when one threshold takes priority over another?

I haven't had any time to think it over, though, and my objections might disappear after seeing some examples.

Tabifier 5.0? I wish it was a matter of days, not weeks! We'll see. I am still trying to find time to finish the last set of tabifier bugs, and the rearranger is popular and in need of attention. I'm trying to prioritize by urgency and by number of people requesting/benefitting from a feature.

Maybe I'll have to start posting a weekly status report, like JetBrains did for -- what -- 3 (non-consecutive) weeks? :)

Comment actions Permalink

Yes, easily done.

Comment actions Permalink

I imagine that a lot of my prettiness concerns will go away with the decoupling of method signature tabification from method call tabification.

Most of the time, assignment spaces are substantially less ugly than method call spaces.

Thanks again for all your time.

Comment actions Permalink

Dave Kriewall wrote:

>What if you could see a copy of your own current file in the preview pane?

That's a good idea.
I thought about asking you for a vaguely similar feature in the
rearranger :
preload the setting list, based on the current file


Comment actions Permalink

Dave Kriewall wrote:

>Yeah, the preview pain. I mean, pane. I thought about putting more stuff in it, but it seems to just get longer and longer. Starts to look like my collection of Junit tests!


Next to the general code example, you could use some extensive
specialized test filed, one per section, that would allow for finer
grained tuning/showing.


Comment actions Permalink

Hi Joe,

Try the 4.4 tabifier; the parameter alignment should be better. I realized that the setting of "Align Expressions" is immaterial when the expression is a parameter. "Align Parameters" takes precedence.

Also, all those weird spacing and indentation problems should be gone. I had to come to grips with continuation lines, something I had tried to gloss over before. It took me a while (and I was also diverted with Rearranger work) but looks solid now.

I hope to start making more rapid changes to tabifier now. I plan to do your two requested features (separate param and method declaration controls, and having 2nd & subsequent parameters just follow the first with no spacing) first, then get to work on a progress bar, then do the adaptive spacing algorithm.

Thanks for your patience!



Please sign in to leave a comment.