4

You and your collaborators have different preferences for how to indent your files.

Obviously they have a barbaric suggestion, whether that's tabs, spaces or something else, doesn't matter, it's wrong, but now they use it anyway.

How can the displayed indentation be controlled in vim, without altering the indentation on disc when the file is is written to?

2 Answers 2

8

As Robert Axelson has already stated, if the file is indented using tabs, this is easily achieved by using :set tabstop, which is designed for this very purpose.

A solution for halving space indents

In the interests of hackery, I came up with this code using Vim 7.3's +conceal feature that allows you to display a file as though the space-based indentation is half what it really is: e.g. it will display a file that uses four spaces for indentation as if uses two spaces instead:

syntax match HalveIndent /\v^( +)\ze\1/ conceal
set conceallevel=2
set concealcursor=nvic

A solution for doubling space indents

Here's an even hackier version that uses a cchar replacement character to double all the space-based indent: e.g. It will display a file indented with two spaces as though it is indented with four spaces.

syntax match DoubleIndent /^ \+/
execute 'syntax match DoubleIndentSpace / / containedin=DoubleIndent contained conceal cchar=' . "\uff0e"
set conceallevel=2
set concealcursor=nvic
highlight Conceal ctermfg=bg guifg=bg

How they work

The +conceal feature allows you to hide certain text in your file. See :help new-conceal for a brief introduction.

The code in the first solution sets up a syntax group HalveIndent that finds stretches of spaces at the start of a line that are multiples of two, and then hides the first half of the spaces using conceal

The code in the second solution sets up a syntax group DoubleIndent that finds space-indents, and then another syntax group DoubleIndentSpaces that finds single spaces within the areas matched by the first group. It then replaces all these spaces with a single Unicode character that will take up two columns on-screen: FULLWIDTH FULL STOP (U+FF0E). (N.B. You could directly insert the character into the command, but in order to make it clearer, I've included it as a string value that is added onto the command with :execute.) Unfortunately there doesn't appear to be a full width space character: the full width full stop is the most discreet character I could find, but you might prefer another character. In any case, we then use a highlight command, to make the displayed character invisible. (Except when the cursor is actually over it.)

Setting conceallevel to 2 means that, when we're not setting a cchar replacement character for the text, it will be completely hidden instead.

By default, concealed text is revealed when the cursor is on the same line. Setting 'concealcursor' to nvic means that the text will remain hidden in all the listed modes — if you were to remove, say, the i from that option, then the text would be revealed when you are in insert mode.

This has the minor downside that when you are moving the cursor within the concealed area, it can move between the concealed characters without actually appearing to move on-screen. If you find this more disorienting that having the concealed text expanding-and-decreasing all the time, you could tweak the concealcursor value (or remove it entirely).

The regular expression used for halving space indents

We are finding whitespace to hide with the regular expression: /\v^( +)\ze\1/.

Broken down:

  • \v – Use "very magic" to require less backslash-escaping,
  • ^ – Match the start of the line: we only want to conceal indent!
  • ( +) – Match one-or-more space characters: as many as possible. We're using parentheses here so we can refer back to what we matched later on.
  • \ze – End the match here: everything after this will not be included in the text that is concealed,
  • \1 – Match whatever text was previously matched by the parenthesis-enclosed group, ( +). So if we previously matched one space, it needs to be followed by another; if we previously matched two spaces, they need to be followed by two more. This means that the whole expression will only match sets of spaces where the number of spaces is a multiple of two.

Further reading:

  • :help syntax
  • :help conceal
  • :help cchar
  • :help \v
  • :help \ze
  • :help \1

Requirements

Both solutions require the +syntax and +conceal features to be compiled in.

The solution for doubling indents also requires +multi_byte to be compiled in, and for encoding to be set to an appropriate value for the unicode string to work (e.g. utf-8).

2

Put this in your .vimrc, and it will define how your tabs are displayed (replacing the number 4 with whatever your preferred number or spaces is):

set tabstop=4

As far as I know, you can only affect how tabs are displayed, and not spaces. So if someone religiously uses 2 spaces for indentation, and you want 4 instead, you can not change that without also writing that change to the file.

UPDATE: .editorconfig

I would strongly encourage you to argue for implementing a .editorconfig file in your project, which will make it much easier to handle this within your team.

2
  • I was familiar with tabstop, but was hoping that there would be something more generic that could work with spaces as well. I'll take a look at editorconfig to see how that can help. Thanks. :)
    – user50849
    Nov 15, 2017 at 9:20
  • @user50849 Yeah, get your point. Please let me know if you do come across something that also handles spaces though. And GL with editorconfig :) Nov 15, 2017 at 9:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.