10

Foreword

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.

Question

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.

6
  • 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
    Commented Oct 26, 2016 at 9:56
  • @Rich: Vim 8.0.0046, confirmed with vim -N -u NONE.
    – intelfx
    Commented Oct 26, 2016 at 16:15
  • Then indent with gI<tab> and unindent with 0x.
    – Antony
    Commented Jan 8, 2017 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
    Commented Jan 8, 2017 at 18:03
  • You'll have to program it, or find a plugin that does that. Or use a simpler indentation scheme.
    – Antony
    Commented Jan 8, 2017 at 18:06

3 Answers 3

2

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.

1
  • 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 😅 Commented Apr 16, 2020 at 17:33
0

: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.

1
  • 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
    Commented Jan 9, 2018 at 10:54
0

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.

3
  • 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
    Commented Jan 29, 2018 at 16:02
  • 1
    Also, why not use Vim's :retab command?
    – Rich
    Commented Jan 29, 2018 at 16:16
  • I've used vi from the original sources of various Unix distros for decades. I've made use of the other tools available because they work and I don't have to remember several things to try in case the version of VI, VIM or otherwise happens to not have that feature.
    – grwww
    Commented Jan 23 at 2:50

Your Answer

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

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