Dealing with code indentation in Vim? - vim

I work on an engineering team of 4 people, mostly writing javascript while occasionally dabbling in ruby and python. So, as a team, we share code all the time, and as most programmers do, each member of the team has his favorite level of indentation & related settings. I am one of 2 members of the team who use and love Vim as my primary code editor. I love my team but I also love my indentation, which happens to use 4-space tab characters. For more context, here's what I use in my .vimrc:
set ts = 4 sts = 4 sw = 4 expandtab " 4 space tabs
With so much code-sharing and collaborative editing going on in the team, the main code files usually start to appear as a mass of mixed tab & space mayhem, so that even the classic Vim trick of selecting all and pressing = to smart indent doesn't have much effect.
Anyway, my question is this: In Vim (MacVim specifically) is there a better (more reliable) way of converting a code file from messy, mixed indentation to my preferred indentation? Whether it be a .vimrc setting or a command I enter while editing the file, I don't care.
Thanks for any suggestions in advance!

Use :retab.
Having said that, I strongly suggest that you, as a team, agree on and use an indentation style when working collaboratively on a certain project.

We have the same case of using javascript and ruby in the same shop.
autocmd FileType * set tabstop=4|set shiftwidth=4
autocmd FileType ruby set tabstop=2|set shiftwidth=2
set expandtab
I find I like 4 spaces for javascript but ruby looks much better with just two spaces.
I do agree with Yaser, you need to set the standard (spaces FTW)
Once you decided to get rid of all the tab chars use grep to find the files to :retab
grep -P '\t' * -R -c

Related

Vim doesn't use tabstop distance in insert-mode

I'm having problems with auto indentation in vim while programming in lisp.
My .vimrc had the following settings for tabs:
set noexpandtab
set autoindent
set softtabstop=0
set shiftwidth=8
set tabstop=8
When I type (if <enter> in insert-mode, a new line is created with an indentation of two spaces.
None of my settings say anything about two spaces, so why don't I get a tab?
What setting can I use to change the indentation while in insert-mode?
Thanks in advance!
Update:
Thanks for the answers, the settings are not overwritten.
It has to do with the "default lisp indenting".
In the :help lisp it says something about changing the p flag in
cpoptions. This is what it says in the help for the cpoptions flags:
p - Vi compatible Lisp indenting. When not present, a slightly better algorithm is used.
Setting it does change the indent to one space instead of two spaces.
Still not sure how to change this to something else though.
Looks like this is two-space indentation is a hard coded behavior of :set lisp mode which ignores shiftwidth.
We can trace this to the source code which contains a hard-coded amount += 2; increment statement.
It's that way for a good reason; it has come to be the predominant way of writing Lisp.
As I wrote this answer, I peeked at samples of source code the following projects (all Lisp or Lisp-like languages):
Steel Bank Common Lisp (SBCL);
Clozure Common Lisp (CCL);
GNU Emacs;
Clojure;
GNU Guile;
Racket;
and GNU CLISP.
I did not spot a single example of anything but two-space indentation! With two-space indentation, you are in good/large company. You might as well get used to that; even if you somehow get Vim to follow your way, if you upstream anything into anyone's Lisp project, you will likely have to reformat.
Now, I have seen Lisp code using four-space indentation, like in very old code bases and some books.
By the way, sometimes you see if indented like this:
(if (condition)
(then)
(else))
This may happen where indentation is four spaces, but I'm referring situations when this is alignment, and not four space indentation. This formatting is, of course, standard for function arguments, but controversial for operators such as if. Some people like it that way in their code bases. For instance, this institution's randomly found coding style guide recommends this way of writing if, while also recommending two-space indentation.
Vim will do the above if you remove if from lispwords.
The :set lispwords=... parameter contains a comma-separated list of identifiers which follow operator-like indentation, meaning two spaces rather than function-like alignment: second and third lines align with argument. By default, if is found in lispwords.
Lisp mode also applies two space indentation to a function (i.e. form not listed in lispwords, if there is no argument):
(gobbledygook 1 2
2 3)
(gobbledygook
1)
That's also "canonical". Sometimes this comes in handy if you're trying to conform to some maximum line length; a function call running past the limit can sometimes be made to fit by moving all its arguments down, and just giving them two space indentation.
Each filetype can have its own settings in vim. So your .vimrc values can be overwritten in filetype plugins. To learn the current values of the settings for lisp filetype open the lisp file and run the following commands in vim command line:
:set noexpandtab?
:set autoindent?
:set softtabstop?
:set shiftwidth?
:set tabstop?
If they are different from the ones in .vimrc, then your values are overwritten in some plugin.
In order to overwrite them again with your custom values, create the ~/.vim/after/ftplugin/lisp.vim file with the required values:
set noexpandtab
set autoindent
set softtabstop=0
set shiftwidth=8
set tabstop=8

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

Vim Configuration: How to expand tabs only when saving?

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?

How do you use indent in vim for web development?

I'm starting to use Linux and Vim at work. I'm started reading vims documentation and creating my own .vimrc file and such.
I'm a web developer working with HTML, XML, CSS, JS, Python, PHP, ZPT, DTML and SQL.
I would like to have an indent feature like this one: for each language/set, a corresponding indent solution.
So, in js, writing function test(){|} would turn in
function test(){
|
}
If php, writing <?php function test(){|}:
<?php
function test(){
|
}
?>
...and such. Writing a function definition in Python, and then creating a for loop sentece, it would automatically create an indent.
I'm starting with autoindent, smartindent, cindent but I'm a little confused about their differences.
How do the indent in vim works? Am I supposed to download plugins for each language? Is the behavior I described possible with already existing plugins you're used to or do I have to create it?
I keep seeing people using Vim and I'm trying to do this as well since the machine I'm using is too limited, but I'm afraid I won't be able to have a decent auto indenting solution in it. And I really think that having to manually indent code all the time (instead of sometimes only) is a waste of time and it's against vim's "MOTTO" I've seen called "productivity".
(I have used autoindenting in a little small project in Visual Studio, and really liked their approach. Is there a plugin for that?)
Vim is usually pretty smart about indenting once you define the correct settings for tab size and the like. (Edit: As Igor mentions in the other answer, be sure to turn on filetype-specific indenting.) It seems that you want vim to automatically insert newlines though, which I don't think it can do without a plugin.
However, I think you may want to look at snipMate, which is a plugin that defines a large number of 'snippets' for different programming languages, and you can also define your own. It's basically a kind of improved tab-completion:
One example:
php<tab>
turns into
<?php
|
?>
With | being your cursor. Some snippets even define multiple cursor-positions which you can switch to with another press of tab.
vim usually comes with a bunch of syntax plugins for different languages. if you want to use those for indenting, you will need:
set autoindent
filetype indent on
you might also need syntax on but i'm not sure if that's needed for indenting. couldn't hurt though...
I found the setup for this based on a blog post:
set autoindent
inoremap {<CR> {<CR>}<Esc>O<Tab>
Having this with snipmate.vim and autoclose.vim is working flawlessly.

Auto formatting for vi?

Does an auto-formatting tool exist for vi that'll allow me to define per language preferences?
edit: I'm not looking for syntax highlighting. I'm looking for something that will apply formatting rules to my code. (Like brace positioning, spaces around oeprators, etc)
Well, there's Vim which comes with a lot of languages covered already and which is easy to customize per language.
Vim has tons of support for filetype-specific customisations. You might find what you are looking for in there.
You can add a file in ~/.vim/ftplugin/ for each file type. For example, set ~/.vim/ftplugin/c.vim to
set tabstop=2 shiftwidth=2
This sets your indentation for C files to two spaces.
You can use vim. If you're on GNU/Linux, take a look at /etc/vim/vimrc for global defaults. Some things you may want are "syntax on" "filetype indent on" and "set showmatch".
There is a vim plugin that enables formatting on your code from within vim. It's called vim-autoformat and you can dowload it here:
https://github.com/vim-autoformat/vim-autoformat
It integrates external code-formatting programs into vim. For example, if you want to format C, C++, C# or Java code, you can install the program astyle, and vim sets it as the format program automatically.
As Darrin says, "flee from the vi wasteland" and embrace the one true vim path instead! Your desired language preferences, assuming that they're not for SNOBOL or Simula, will thank you!
Edit: Actually extending the syntax highlighting to cover SNOBOL or Simula would not be that hard! (-:

Resources