Vim 7.2 Formatting Code

Exclusive offer: get 50% off this eBook here
Hacking Vim 7.2

Hacking Vim 7.2 — Save 50%

Ready-to-use hacks with solutions for common situations encountered by users of the Vim editor

$23.99    $12.00
by Kim Schulz | April 2010 | Linux Servers Open Source

This article by Kim Schulz, author of Hacking Vim 7.2, will have recipes in two categories:

  • Code formatting
  • Using external formatter programs

Formatting code often depends on many different things. Each programming language has its own syntax, and some languages rely on formatting like indentation more than others. In some cases, the programmer is following style guidelines given by an employer so that code can follow the company-wide style.

So, how should Vim know how you want your code to be formatted? The short answer is that it shouldn't! But by being flexible, Vim can let you set up exactly how you want your formatting done.

However, the fact is that even though formatting differs, most styles of formatting follow the same basic rules. This means that in reality, you only have to change the things that differ. In most cases, the changes can be handled by changing a range of settings in Vim. Among these, there are a few especially worth mentioning:

  • Formatoptions: This setting holds formatting-specific settings (see :help 'fo')
  • Comments: What are comments and how they should be formatted (see :help 'co')
  • (no)expandtab: Convert tabs to spaces (see :help 'expandtab')
  • Softtabstop: How many spaces a single tab is converted to (see :help 'sts')
  • Tabstop: How many spaces a tab looks like (see :help 'ts')

With these options, you can set nearly every aspect of how Vim will indent your code, and whether it should use spaces or tabs for indentation. But this is not enough because you still have to tell Vim if it should actually try to do the indentation for you, or if you want to do it manually. It you want Vim to do the indentation for you, you have the choice between four different ways for Vim to do it. In the following sections, we will look at the options you can set to interact with the way Vim indents code.

Autoindent

Autoindent is the simplest way of getting Vim to indent your code. It simply stays at the same indentation level as the previous line. So, if the current line is indented with four spaces, then the new line you add by pressing Enter will automatically be indented with four spaces too. It is then up to you as to how and when the indentation level needs to change again. This type of indentation is particularly good for languages where the indentation stays the same for several lines in a row. You get autoindent by using :set, autoindent, or :set ai.

Smartindent

Smartindent is the next step when you want a smarter indent than autoindent. It still gives you the indentation from the previous line, but you don't have to change the indentation level yourself. Smartindent recognizes the most common structures from the C programming language and uses this as a marker for when to add / remove the indentation levels. As many languages are loosely based on the same syntax as C, this will work for those languages as well. You get smart indent by using any of the following commands:

  • :set smartindent
  • :set si

Cindent

Cindent is often called clever indent or configurable indent because it is more configurable than the previous two indentation methods. You have access to three different setup options:

cinkeys

This option contains a comma-separated list of keys that Vim should use to change the indentation level. An example could be: :set cinkeys="0{,0},0#,:", which means that it should reindent whenever it hits a {, a } or a # as the first character on the line, or if you use : as the last character on the line (as used in switch constructs in many languages).The default value for cinkeys is "0{, 0}, 0), :, 0#, !^F, o, O, and e". See :help cinkeys for more information on what else you can set in this option.

cinoptions

This option contains all the special options you can set specifically for cindent. A large range of options can be set in this comma-separated list. An example could be:set cinoptions=">2,{3,}3", which means that we want Vim to add two extra spaces to the normal indent length, and we want to place { and } three spaces as compared to the previous line. So, if we have a normal indent to be four spaces, then the previous example could result in the code looking like this (dot marks represent a space):

if( a == b)

...{

......print "hello";

...}

The default value for cinoptions is this quite long string: ">s,e0,n0,f0,{0,}0,^0,:s,=s,l0,b0,gs,hs,ps,ts,is,+s,c3,C0,/0,(2s,us,U0,w0,W0,m0,j0,)20,*30" . See :help 'cinoptions' for more information on all the options.

cinwords

This option contains all the special keywords that will make Vim add indentation on the next line. An example could be: :set cinwords="if,else,do,while,for,switch", which is also the default value for this option. See :help 'cinwords' for more information.

Indentexpr

Indentexpr is the most flexible indent option to use, but also the most complex. When used, indentexpr evaluates an expression to compute the indent of a line. Hence, you have to write an expression that Vim can evaluate. You can activate this option by simply setting it to a specific expression such as:

:set indentexpr=MyIndenter()

Here, MyIndenter() is a function that computes the indentation for the lines it is executed on.

A very simple example could be a function that emulates the autoindent option:

function! MyIndenter()
" Find previous line and get its indentation
let prev_lineno = s:prevnonblank(v:lnum)
let ind = indent( prev_lineno )
return ind
endfunction

Adding just a bit more functionality than this, the complexity increases quite fast. Vim comes with a lot of different indent expressions for many programming languages. These can serve as inspiration if you want to write your own indent expression. You can find them in the indent folder in your VIMHOME.

You can read more about how to use indentexpr in :help 'indentexpr' and :help 'indent-expression'.

Fast code-block formatting

After you have configured your code formatting, you might want to update your code to follow these settings. To do so, you simply have to tell Vim that it should reindent every single line in the file from the first line to the last. This can be done with the following Vim command:

1G=G

If we split it up, it simply says:

1G: Go to the first line of the file (alternatively you can use gg)

=: Equalize lines; in other words, indent according to formatting configuration

G: Go to the last line in the file (tells Vim where to end indenting)

You could easily map this command to a key in order to make it easily accessible:

:nmap <F11> 1G=G
:imap <F11> <ESC>1G=Ga

The last a is to get back into the insert mode as this was where we originally were. So, now you can just press the F11key in order to reindent the entire buffer correctly.

Note that if you have a programmatic error, for example, missing a semicolon at the end of a line in a C program, the file will not be correctly indented from that point on in the buffer. This can sometimes be useful to identify where a scope is not closed correctly (for example, a { not closed with a } ).

Sometimes, you might just want to format smaller blocks of code. In those cases, you typically have two options—use the natural scope blocks in the code, or select a block of code in the visual mode and indent it.

The last one is simple. Go into the visual mode with, for example,Shift+v and then press = to reindent the lines.

When it comes to using code blocks on the other hand, there are several different ways to do it. In Vim, there are multiple ways to select a block of code. So in order to combine a command that indents a code block, we need to look at the different types and the commands to select them:

i{

Inner block, which means everything between { and } excluding the brackets. This can also be selected with i} and iB.

a{

A block, which means all the code between { and } including the brackets. This can also be selected with a} and aB.

i(

Inner parenthesis, meaning everything between ( and ) excluding the parentheses. Can also be selected with i) and ib.

a(

A parentheses, meaning everything between ( and ) including the parenthesis. Can also be selected with a) and ab.

i<

Inner < > block, meaning everything between < and > excluding the brackets. Can also be selected with i>.

a<

A < > block, meaning everything between < and > including the brackets. Can also be selected with a>.

i[

Inner [ ] block, meaning everything between [ and ] excluding the square brackets. Can also be selected with i].

a[

A [ ] block, meaning everything between [ and ], including the square brackets. This can also be selected with a].

So, we have defined what Vim sees a block of code as; now, we simply have to tell it what to do with the block. In our case, we want to reindent the code. We already know that = can do this. So, an example of a code block reindentation could look like this:

=i{

Let's execute the code block reindentation in the following code (| being the place where the cursor is):

 
if( a == b )
{
print |"a equals b";
}

This would produce the following code (with default C format settings):

if( a == b )
{
print |"a equals b";
}

If, on the other hand, we choose to use a { as the block we are working on, then the resulting code would look like this:


if( a == b )
{
print "a equals b";
}

As you can see in the last piece of code, the =a{ command corrects the indentation of both the brackets and the print line.

In some cases where you work in a code block with multiple levels of code blocks, you might want to reindent the current block and maybe the surrounding one. No worries, Vim has a fast way to do this. If, for instance, you want to reindent the current code block and besides that want to reindent the block that surrounds it, you simply have to execute the following command while the cursor is placed in the innermost block:

=2i{

This simply tells Vim that you will equalize / reindent two levels of inner blocks counting from the "active" block and out. You can replace the number 2 with any number of levels of code blocks you want to reindent. Of course, you can also swap the inner block command with any of the other block commands, and that way select exactly what you want to reindent.

So, this is really all it takes to get your code to indent according to the setup you have.

Auto format pasted code

The trend among programmers tells us that we tend to reuse parts of our code, or so-called patterns. This could mean that you have to do a lot of copying and pasting of code.

Most users of Vim have experienced what is often referred to as the stair effect when pasting code into a file. This effect occurs when Vim tries to indent the code as it inserts it. This often results in each new line to be indented to another level, and you ending up with a stair:

code line 1
code line 2
codeline 3
code line 4
...

The normal workaround for this is to go into the paste-mode in Vim, which is done by using:

:set paste

After pasting your code, you can now go back to your normal insert mode again:

:set nopaste

But what if there was another workaround? What if Vim could automatically indent the pasted code such that it is indented according to the rest of the code in the file? Vim can do that for you with a simple paste command.

p=`]

This command simply combines the normal paste command (p) with a command that indents the previously inserted lines (=`]). It actually relies on the fact that when you paste with p (lowercase), the cursor stays on the first character of the pasted text. This is combined with `], which takes you to the last character of the latest inserted text and gives you a motion across the pasted text from the first line to the last.

So, all you have to do now is map this command to a key and then use this key whenever you paste a piece of code into your file.

Using external formatting tools

Even though experienced Vim users often say that Vim can do everything, this is of course not the truth—but is close. For those things that Vim can't do, it is smart enough to be able to use external tools.

In the following sections, we will take a look at some of the most used external tools that can be used for formatting your code, and how to use them.

Hacking Vim 7.2 Ready-to-use hacks with solutions for common situations encountered by users of the Vim editor
Published: April 2010
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:

Indent

The Indent program is probably one of the most used external programs for Vim. It has been around since the late 80s for various Unix platforms, and has also later been imported to other platforms including Microsoft Windows.

As the name indicates, this program indents code—especially the code that resembles the C code in syntax. What you may wonder is why you would use an external program for this when Vim can handle this task just fine. This is a good question because Vim can do this very well, but the Indent program does it better and at the same time makes it easier to standardize the indentation among multiple editors.

By specializing only in indenting code, indent is able to indent code more effectively than the limited indent functionality included in Vim, for which indenting is "a feature" and not "the feature". Indent specializes in understanding the code and indents it according to the code—even if there is a syntactic error in the code.

So, how do you use Indent from within Vim? Previously, we have seen several different options for how Vim should indent your code. There is, however, one option that overrules all of them:

:set equalprog=PROGRAM

What this option does is set the external program that Vim should use for indentation when using the commands with = . In the case of Indent, you simply change PROGRAM to the path to your Indent program. Now, whenever you use one of the indentation commands such as 1G=G, it takes the involved lines and pipes them through the program you have defined in equalprog. You can even supply the program with command-line arguments if needed.

In the case of Indent, there are so many different command-line arguments that you will get a better result by configuring its configuration file.

You can always find the latest version of the Indent program at this address: http://www.gnu.org/software/indent/.

Berkeley Par

In the early 90s, Adam M. Costello began working on a simple command-line program whose only purpose was to reformat a given text with a paragraph in it according to the user's wishes. The program was called Par and, within a year or two, it evolved into a very feature-rich program that could reformat nearly any type of paragraph.

This, of course, makes Par an ideal external friend for Vim. So, let's look at some examples of how it can be used.

If, for instance, you want your text to be nicely formatted in paragraphs with no more than 78 characters on each line, then you could simply use it as:


:set formatprg=par\ -w78

The formatprg option in Vim tells it which program to use for formatting of the text when one of the gq commands is used. Notice that the space between the program name and its option is escaped with a backslash. This is needed in order for Vim to see the entire string as one option and not two.

Note that Vim will only use formatprg when formatexpr is empty. Otherwise, the formatexpr will be used.

From earlier on, we know that Vim cannot justify the text such that both ends of the lines are aligned with the margins. Fortunately, Par can help us here. By simply adding a j (for "justify") to our previous formatprg value, we can get Par to justify the text:

:set formatprg=par\ -w78j

Par cannot only be used on a normal text, but also on some parts of the code—the comments.

If you, for instance, have the following comment:

/********************************************************************/
/* This function helps you modify a string and remove all */
/* unnecessary characters . */
/* Don't use this on widechar strings or strings shorter than 10 */
/* characters */
/********************************************************************/

You could select it in Vim and then do:

!par 60r

(Vim adds '<, '> in front of ! as a range).

This will give you the following result:

/**********************************************************/
/* This function helps you modify a string and remove all */
/* unnecessary characters . Don't use this on widechar */
/* strings or strings shorter than 10 characters */
/**********************************************************/

With a single command, you have transformed an ugly, unformatted comment into a nicely formatted and aligned comment.

The manual page for Par gives a lot of examples on what else it is capable of.

You could easily map different Par commands to different keys in Vim and this way have formatting keys for all text, comments, lists, and so on.

Tidy

If you work with web development or XML files, the tidy program could easily become your next best friend besides Vim. This program cleans up the code that is fed to it and makes it compliant for the World Wide Web Consortium (W3C) . Being W3C-compliant means that the code is constructed such that it follows the HTML guidelines set by the (W3C).

As a web programmer, I once in a while get in a situation where I have to open someone else's HTML or XML file only to find that it is one big mess. Because of this, I run all files with the .xml, .htm, or .html extension through tidy when opening it. This is done using autocommands (au for short) in Vim, which I have added to my vimrc file.

For XML this looks as follows:

au FileType xml exe ":silent 1,$!tidy --input-xml true --indent yes
-q"

For HTML files, it looks like this:

au FileType html,htm exe ":silent 1,$!tidy --indent yes -q"

Please note that this will alter the file you open without you knowing anything about what it has changed. In both cases, Vim expects to find a program called tidy in your path, no matter if you are in Linux or Windows.

As you can see from the arguments I have given for the tidy program, it can also be used for reformatting the indentation of the HTML / XML. This option makes the file very readable and it gets a lot easier to get an overview of a file after opening it.

Since tidy checks for errors in the document, you could assign it to a key, so that at any time you could check if the changes you have made are in fact W3C compliant.

You can always find the latest version of tidy here at: http://tidy.sourceforge.net/.

Summary

In this article, we have looked at how to get better at formatting our code.

We looked at how to format your code in Vim, and especially how to indent code. We learned that since we all have our own special coding style, it is often hard to make a generic functionality for code formatting. Vim handles this by giving the user a flexible interface for setting up exactly how he or she wants it to format the code. We also looked at a couple of recipes for how we can format a block of code fast, and even how to format the code that you paste into Vim from other places.

Finally, we took a look at how we can use an external tool to give Vim that extra edge it needs to be the perfect editor. External tools can help you format both text and code, and we took a short look at some of the most popular ones to see how they can work together with Vim.


If you have read this article you may be interested to view :

Hacking Vim 7.2 Ready-to-use hacks with solutions for common situations encountered by users of the Vim editor
Published: April 2010
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:

About the Author :


Kim Schulz

Kim Schulz has an M.Sc. in Software Engineering from Aalborg University in Denmark. He has been an active developer in the Linux and Open Source communities since 1997 and has worked with everything from translation and bug fixing to producing full-blown software systems. This entire time, Vim has been Kim's editor of choice and it has been the first thing he installs whenever he sits by a new computer. Today Kim works as a full-time software engineer at CSR Plc. developing software for the next generation wireless technologies. A lot of Kim's spare time has been spent on developing the open-source CMS Fundanemt. This has lead to him now owning the web-hosting company Devteam Denmark that specializes in hosting and development of Fundanemt-based websites.

Books From Packt


jQuery 1.4 Reference Guide
jQuery 1.4 Reference Guide

Getting started with Audacity 1.3
Getting started with Audacity 1.3

iReport 3.7
iReport 3.7

Zabbix 1.8 Network Monitoring
Zabbix 1.8 Network Monitoring

Hacking Vim: A Cookbook to get the Most out of the Latest Vim Editor
Hacking Vim: A Cookbook to get the Most out of the Latest Vim Editor

Cacti 0.8 Network Monitoring
Cacti 0.8 Network Monitoring

FreePBX 2.5 Powerful Telephony Solutions
FreePBX 2.5 Powerful Telephony Solutions

Asterisk 1.4 – the Professional’s Guide
Asterisk 1.4 – the Professional’s Guide


Your rating: None Average: 5 (1 vote)

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
X
S
u
L
x
L
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software