Vim Configuration: How to expand tabs only when saving? - vim

I love tabs, and prefer it to spaces in indentation.
But I'd like to transform tabs into 4-space groups when saving files. (Because the file may be opened and edited in other environments) And of course, those generated spaces should be converted back to tabs if I open the file again. (Assume that there are no 4 contiguous spaces in the original text)

Well in your .vimrc:
set noexpandtab
set tabstop=4
set shiftwidth=4
fun MyRetab()
set expandtab
retab
set noexpandtab
endfun
au FileWritePre *.YOURFILEEXTENSION call MyRetab()
But I don't know what you mean by "those spaces should be still recognized as tabs if I open the file again."
If you write a file spaces instead of tabs, well it can't be undone easily AFAIK. EDIT: see the super retab wiki page for undoing it!
NOTE if you have tab(s) in your source's string contents this will replace that as well!

In addition to Zsolt Botykai's answer, you could try using retab!, which attempts to replace spaces with tabs where appropriate. This seemed to work quite well when I just tried it, but I got a few erroneous tabs. I suppose it depends how good your assumption is that there no other sequences of 4 spaces other than expanded tabs.
HOWEVER... this all seems like a risky business. In my experience, when there are coding/encoding standards such as these, it is always easiest to adhere to them from the start. "Fixing-up" the file in this way is asking for trouble.
I think Vim does a good job of emulating tab-like behaviour while using only spaces. Have you tried using smarttab and expandtab?

Related

Have vim ai obey the formatting of spaces from the previous line

When I indent/format my code I use tabs for indentation, spaces for alignment. I feel that this is intuitive and very effective at keeping code nicely formatted independent of the tab width of other programmers (as long as they are using monospace).
I like to keep my code nicely formatted for other potential developers and this is one thing about vim that irks me and I want to know if there is a solution. Using the ai format in vim if you have a line that is 2 tabs followed by 9 spaces (assuming 4 space wide tabs) when you enter a new line vim will have the new line be 4 tabs and 1 space. Which is not the desired behavior( I would like it to be 2 tabs and 9 spaces, like the previous line).
My question is, is this even possible? If no, why not? If yes, how do I do it?
Try this in your ~/.vimrc:
set noexpandtab
set copyindent
set preserveindent
set softtabstop=0
set shiftwidth=4
set tabstop=4
It will add spaces though, if your current indentation is not a multiple of tabstop.

Can vim recognize indentation styles (tabs vs. spaces) automatically?

I'm working on a large codebase, where each file has different indentation conventions: tabs, 4 spaces, 3 spaces, etc.
I currently default on tabs and do set shiftwidth=N expandtab smarttab when I come across a spaces-indented file, but that's annoying.
Is there any functionality in Vim, or a plugin, which can recognize that, for instance, the current buffer uses an indentation with three spaces per shift?
Various plugins exist that attempt to handle that situation. Here are a few I found by search for detect indent at vim.org
sleuth
DetectIndent
yafia
IndentConsistencyCop
IndentFinder
Good question,I'm facing the same problem too, and recently I wrote such a vim plugin for myself:https://github.com/luochen1990/indent-detector.vim
it has the following features:
detect mixed indent and echo warnning on bufEnter and bufWrite
automatically.
switch setting about indenting to fit the current indenting style automatically.
detecting time is limited, so you don't
need to worry about opening huge files.
I think it is well designed, and need to be known, post an issue on github if you have any suggestion :)

Disable all auto indentation in vim

In TeX vim usually screws up my indentation. Mainly when I'm in a displayed equation which I think should look like this:
\[
x=\frac{y}{z}
\]
where the whitespace infront of the x is one tab.
When I start type the equation I type the \[ and \] marks first and then go back between them, typing the tab and then the rest of the equation.
Vim doesn't do anything wrong until I have to use something that incorporates curly braces (\frac{} for example). When I type the closing } vim automatically shifts the indentation for the whole line to the left, which undoes my typed tab.
This is very anoying, how do I disable it?
my .vimrc contains:
"indentation
set smartindent
set autoindent
set tabstop=5
set shiftwidth=5
filetype indent on
I just spent a few hours working through indentation pains with javascript, and the conclusion I came to is don't remove filetype indent on from your vimrc!
This setting provides the best smart indentation for multiple file types. If you're getting bad results with this, there's likely a configuration issue at hand.
File Specific Indent Settings
So if you're like me, you probably had filetype indent on in your vimrc and had no idea what it was doing.
All this setting does is tell vim to look for files with filetype-specific indent rules. There are a few places it looks, but there are probably only two that you'd be interested in.
$VIMRUNTIME/indent/
~/.vimrc/after/indent/
The first place holds the default indent rules that come with vim. If you were to set filetype indent on on a fresh vim installation, this is where all the smart indenting would come from. For example, when you open a file called index.html in would get the rules from $VIMRUNTIME/indent/html.vim.
In my experience, these default rules are pretty darn good, but they can get messed up by other settings.
The second place (the after directory) allows you to add settings that will supercede those in the first place. This is nice because you don't have to edit the default files in order to customize them.
Flavors of Indentation
There are a few different indentation options as you've seen, and they don't all play nice together. From the Vim wiki:
autoindent
'autoindent' does nothing more than copy the indentation from the previous line, when starting a new line. It can be useful for structured text files, or when you want to control most of the indentation manually, without Vim interfering. 'autoindent' does not interfere with other indentation settings, and some file type based indentation scripts even enable it automatically.
I use filetype indent on and set autoindent in my vimrc, since they work well together. I don't have the others set.
smartindent & cindent
'smartindent' automatically inserts one extra level of indentation in some cases, and works for C-like files. 'cindent' is more customizable, but also more strict when it comes to syntax.
'smartindent' and 'cindent' might interfere with file type based indentation, and should never be used in conjunction with it.
When it comes to C and C++, file type based indentations automatically sets 'cindent', and for that reason, there is no need to set 'cindent' manually for such files. In these cases, the 'cinwords', 'cinkeys' and 'cinoptions' options still apply.
Generally, 'smartindent' or 'cindent' should only be set manually if you're not satisfied with how file type based indentation works.
indentexpr
Runs filetype indent scripts found in (vimfolder)\indent\\(indentscripts). It is mentioned in the vim documentation for filetype, alongside the others just mentioned (also, it was the cause of the problem I was having):
Reset 'autoindent', 'cindent', 'smartindent' and/or 'indentexpr' to disable indenting in an opened file.
Troubleshooting
There's a chance that some rogue plugin is changing your indent settings and that's why you're getting poor results. Luckily verbose will tell you which file was the last to change the option in question.
:verbose set autoindent?
:verbose set cindent?
:verbose set smartindent?
:verbose set indentexpr?
You may get a result such as
indentexpr=SomeMessedUpValue
Last set from ~/.vim/bundle/some_plugin/indent/plaintex.vim
If that happens, you can move that file, close and open vim, and see if it fixes your problem.
Turning Off Indent Settings for TeX
Maybe the defaults just aren't doing it for you, and you want to disable the indent settings for TeX, but leave all other file types alone. You can easily do so by setting these values to their defaults in a file in the after directory.
I don't know much about Tex or LaTex, but when I created a file with the .tex extension and ran :filetype it had the filetype as plaintex. Assuming that this is correct, you'd want to create a file, ~/.vim/after/indent/plaintex.vim. In that file:
set autoindent&
set cindent&
set smartindent&
set indentexpr&
This will set all these values to their defaults whenever you open a .tex file.
There seem to be a little mix of terms in your question. In vim the term autoindent points to a special kind of indentation that simply follows the indent level of the previous line (which is quite handy sometimes). To remove it set noautoindent by hand, or write it in your _vimrc.
There are two other automatic kinds of indentation, cindent and smartindent. Similarly, if you wish to disable them go with set nocindent and set nosmartindent
If you look in help (help autoindent, ...) they are all quite nicely explained. Which one you prefer (or don't) is mostly determined by your programming style and habits. So, try them out and see which you like most.
Unfortunatelly, I don't use LaTeX that much anymore, so I'm not familiar with its internal filetype indentation rules.
For anyone else having a similar problem, a solution that worked for me was:
Use :verbose set indentexpr? to find what file was causing the de-indentation
Find where indentexpr is changed (for me it was setlocal indentexpr=GetTeXIndent())
Change that line to setlocal indentexpr& to turn indentexpr off
This removed all de-indenting from brackets, parentheses, and braces.
Remove the lines set autoindent and set smartindent to remove all vim autoindentation.
The following command finally stopped VIM from pretending it knows how to indent files for me and only do what I explicitly tell it:
:setl noai nocin nosi inde=
Courtesy https://vim.fandom.com/wiki/How_to_stop_auto_indenting
If you are using the vim-latex plugin, set this option:
let g:tex_indent_brace=0
For other plugins, if you don't want to turn off indentexpr as in the above answers, you can find where indentkeys is set and comment out those lines. This should stop triggering re-indent when you type a closing brace.
:verbose set indentkeys?

My tab spaces do not align properly - VIM

I'm currently collaborating with a colleague on a project and we both use Vim to code.
However I've noticed that my code does not align the same way as his does and this causes some extra work on his part to re-indent the code.
So I turn on :set list to see to see the differences in tab space marked with (^I) and line endings marked with $.
For some reason when I type in (:list) mode my text does not indent or even show traces of tab markers (^I) similarly to his code. Why is this?
Here's an example of what I mean:
^I^I$this->greeting('Hello world');$
Whilst my code would show up like this in the same file:
$this->reply('Hello you');$
Notice the uneven space?
These are my vimrc settings:
set expandtab
set softtabstop = 4
set tabstop = 4
set shiftwidth = 4
I hope I'm on the right track, there may be some other problem that I haven't considered. Please do share your knowledge on the matter.
Sincerely,
Why
set expandtab means that typed tabs become spaces. This is fine, as long as you both agree on what a tab is; chances are they're using the Unix- (and, I think for historical reasons, vim-) default set tabstop=8.

How to avoid indentation error after changing tab stops in Vim?

I used to have 8-space tabs in Vim. Then I changed to 4 spaces, but now whenever I add a line to some code I had written before changing to 4 spaces, it gives me an indentation mismatch error even though everything is lining up nicely. Is there any way to avoid this problem?
Have you done a :%retab ...?
Have you changed just the tabstop option?
I use 4 spaces (fill with spaces when I hit tab, to insert actual tab hit ctrl-v tab). Here are the tab related settings from .vimrc:
" tabs
set tabstop=4
set shiftwidth=4
set expandtab
When you fill tab with spaces you will always insert spaces instead of tab and your code will always look the same.
When you use tabs each tool displays tab differently and you end up spending your time setting up how many spaces should be displayed for tab (8,4,3.5) instead of doing productive work.
Or choose one of these (from vim 7.1 help tabstop):
Note: Setting 'tabstop' to any other value than 8 can make your file
appear wrong in many places (e.g., when printing it).
There are four main ways to use tabs in Vim:
1. Always keep 'tabstop' at 8, set 'softtabstop' and 'shiftwidth' to 4
(or 3 or whatever you prefer) and use 'noexpandtab'. Then Vim
will use a mix of tabs and spaces, but typing <Tab> and <BS> will
behave like a tab appears every 4 (or 3) characters.
2. Set 'tabstop' and 'shiftwidth' to whatever you prefer and use
'expandtab'. This way you will always insert spaces. The
formatting will never be messed up when 'tabstop' is changed.
3. Set 'tabstop' and 'shiftwidth' to whatever you prefer and use a
|modeline| to set these values when editing the file again. Only
works when using Vim to edit the file.
4. Always set 'tabstop' and 'shiftwidth' to the same value, and
'noexpandtab'. This should then work (for initial indents only)
for any tabstop setting that people use. It might be nice to have
tabs after the first non-blank inserted as spaces if you do this
though. Otherwise aligned comments will be wrong when 'tabstop' is
changed.
For python code, you are probably best off with the following:
:set tabstop=8
:set shiftwidth=4
:set expandtab
That way you are still using the 'industry standard' 8 space tabs, but you won't be putting any of them into your file. That should keep your old code clean as well, although you'll have to go back through and manually move everything left over time. You'll definitely want to :retab everything too.
If you want to replace everything with 4 space indents do
:set tabstop=4
:retab
:set tabstop=8
This will re-indent everything using spaces at 4 spaces per tab, and set you back to sane defaults.
Obvously, this is subject to opinion, but in my book using tabs set to anything other than what you get when you cat the file is asking for trouble.
The best way to visualise a mismatch is to :set list which will show whitespace issues.
set listchars=tab:>-,trail:-,nbsp:+ "This is terminal friendly but you can make fancy
set list
I'd say this is an essential setting for python editing when spaced indents are the norm. Especially when a file is edited by a co worker.
I also double checked the style guideunder "Code lay-out". theres a python -tt option you might want to use as specified in http://www.python.org/dev/peps/pep-0008/. That will throw warnings and errors if you mix tabs with spaces.
You could incorporate this into your unit testing. It seems the pep is recommending 4 spaces for newer code. You might want to consider changing if you intend on contributing to open source projects.
also to be extra tidy I have for deleting whitespace at eol
nnoremap <leader>wd :%s/\s\+$//<cr>

Resources