I'm using the "indent with tabs, align with spaces" ideology for indentation. This means that each line in a file can be prefixed with an arbitrary amount of tabs and spaces (as opposed to "only spaces" or "tabs when possible, then 0 ≤ x < tabstop spaces"). For example:

<--># use OLS (ordinary least squares) to find initial guesses
<-->if prefit or initial is None:
<--><-->beta, cov = sp_opt.curve_fit(model,
<--><-->.............................xdata = x,
<--><-->.............................ydata = y,
<--><-->.............................sigma = yerr,
<--><-->.............................absolute_sigma = True,
<--><-->.............................maxfev = int(1e6),
<--><-->.............................p0 = initial)

Here, a <--> represents a tab character and . represents a whitespace.

To work in this mode, I have noexpandtab set in my vimrc. Hence this question on Vim SE is not relevant for me.


When I shift such a line left or right using << or >> Vim operations, Vim replaces (almost) all existing spaces with tabs. How to avoid this?

I want Vim to only do exactly what's said — i. e. insert or remove a single tab character at position 0 of the line.

  • 2
    I can't reproduce this problem in Vim 7.4.2196 when I run Vim with vim -Nu NONE. What version of Vim are you using? – Rich Oct 26 '16 at 9:56
  • @Rich: Vim 8.0.0046, confirmed with vim -N -u NONE. – intelfx Oct 26 '16 at 16:15
  • Then indent with gI<tab> and unindent with 0x. – Antony Jan 8 '17 at 17:37
  • @Antony: How do I make this work with multiline selections and bind this to > and < respectively, replacing default indent/unindent actions? If possible, then please turn this into an answer. – intelfx Jan 8 '17 at 18:03
  • You'll have to program it, or find a plugin that does that. Or use a simpler indentation scheme. – Antony Jan 8 '17 at 18:06

With the help of this, this, and this, I come up with this:

nnoremap >> 0i<tab><esc>^
nnoremap << :norm 0ldF<tab><enter>^

For multiline selection (works on VISUAL, VISUAL BLOCK and VISUAL LINE):

vnoremap > :norm 0i<tab><enter>gv
vnoremap < :norm 0ldF<tab><enter>gv

Put them on your ~/.vimrc.

| improve this answer | |
  • Good solution, but note it won't work for >[motion], like >} to indent a paragraph; need some more mappings for that. I'd suggest which, but to be honest I never quite understood how to map something which accepts motions 😅 – Martin Tournoij Apr 16 at 17:33

:nnoremap >> I<tab><esc>^

:nnoremap << :s/\v^\t//<cr>

The first one will insert a tab at the start of the current line, without breaking any other characters.

The second one deletes the first character on the line only if it's a tab (by searching and replacing it with nothing). If you have hlsearch on, you can add a :noh call to the end of the second one to get rid of the highlighted residue.

| improve this answer | |
  • The I command will insert text before the first non-blank character of the line, which will break on lines that include space-alignment (such as the OP's line starting xdata). Use 0i or gI instead. – Rich Jan 9 '18 at 10:54

Two things. If you really want to mix tabs and spaces, you really need to count on all spaces that are a complete tab stop, to be replaced with a tab. If you are having problems with using such a file for printing, or viewing on a web page or some other place where tab expansion there, is different than what you are using for editing, then filter your file through 'pr -te ' and that will remove all tabs and replace them with spaces.

I use 'pr -te 8' on files with odd tab practices and then do ":set ts=8 sw=8', '1G' '>G', '<G' and then ':set ts=4 sw=4' to use the tab expansions I use. There are all kinds of complaints about tabs vs spaces which have been on going for decades. In the end, the use of leading tabs produces a lot less hassle for formatting than 'spaces' does, and I can edit a lot faster in VI if I can use 'space' and 'backspace' to move past indentation levels than have to use 'l' and 'h' which require a hand position switch and typically a glance at the keyboard.

When you are just typing a new program, IDEs and other places where auto indent is done for you, you can feel comfortable and just ignore leading spaces. But in the end, it just creates problems when another person can't change indentation levels for themselves, to make the code more readable.

| improve this answer | |
  • 3
    If you are using the OP's indentation style and your goal is to be able to change the size of a tabstop without breaking indentation, then you definitely should not replace all spaces that add up to a tabstop with tabs. Doing so will cause all your spaces-for-alignment indents to break when the size of a tab is changed. (e.g. the xdata line in the OP's example). – Rich Jan 29 '18 at 16:02
  • 1
    Also, why not use Vim's :retab command? – Rich Jan 29 '18 at 16:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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