10
votes

I've already read several questions and answers:

But none of them offers a solution for me.

I really want to apply the "Indent with tabs, align with spaces" principle, but when it comes to auto-indentation, I failed to teach Vim how to do that right.

Consider the code, assuming tabstops == 3, shiftwidth == 3

(>-- means tab, and . (a dot) means space):

{
>--long a = 1,
>-->--..b = 2,
>-->--..c = 3;
}

So, it indents with tabs as much as possible, and then fills the rest with spaces. But it is actually a very bad approach: when someone will read this code with different tab size, the code will be messed up. Here what it will look like with tab size equal to 8 chars:

{
>-------long a = 1,
>------->-------..b = 2,
>------->-------..c = 3;
}

It is horrible. The problem is that Vim doesn't distinguish between indentation and alignment.

To make it look correctly with whatever the tab size is, the code should be indented this way:

{
>--long a = 1,
>--.....b = 2,
>--.....c = 3;
}

Then, this code will look nice whatever that tab size is. For example, 8 chars:

{
>-------long a = 1,
>-------.....b = 2,
>-------.....c = 3;
}

How to achieve this?

2
Maybe the plugin tabular would give you what you are looking for? github.com/godlygeek/tabularZach

2 Answers

4
votes

The most powerful way to influence indenting in Vim is via 'indentexpr'. From its :help:

The expression must return the number of spaces worth of indent. It can return "-1" to keep the current indent (this means 'autoindent' is used for the indent).

As this returns the number of spaces, not the rendered indent itself, and Vim only so far supports tab-, space-, or maximal-number-of-tab-followed-by-spaces (called softtabstop), this cannot be done.

So, if you really want to use this indent method (I personally like it for its purity and elegance, too! (but I don't employ it)), you have to turn off auto-indenting and auto-formatting and do the entire stuff manually by yourself, unfortunately.

-1
votes

As you already pointed out, vim cannot distinguish if you're pressing tab to indent or because you're trying to align text, so is not possibile to automatize the behaviour you want.

Closest thing you can do is to try to play with softtabstop and different values for tabstop, but this way you get the reverse of what you asked for: pressing a tab is going to insert as much spaces possibile before using a tab.

On a side note, if you want your code to always look like you intended, you could try directly setting expandtab.

Spaces always look the same, so

{
.........long a = 1,
..............b = 2,
..............c = 3;
}

is how your code will always appear.