Smart Wrap in Vim

VimWord Wrap

Vim Problem Overview


I have been wondering if Vim has the capability to smart wrap lines of code, so that it keeps the same indentation as the line that it is indenting. I have noticed it on some other text editor, such as e-text editor, and found that it helped me to comprehend what I'm looking at easier.

For example rather than

<p>
    <a href="http://www.example.com">
        This is a bogus link, used to demonstrate
an example
    </a>
</p>

it would appear as

<p>
    <a href="somelink">
        This is a bogus link, used to demonstrate
        an example
    </a>
</p>

Vim Solutions


Solution 1 - Vim

This feature has been implemented on June 25, 2014 as patch 7.4.338. There followed a few patches refining the feature, last one being 7.4.354, so that's the version you'll want.

:help breakindent
:help breakindentopt

Excerpts from vim help below:

'breakindent'     'bri'   boolean (default off)
			              local to window
			              {not in Vi}
			              {not available when compiled without the |+linebreak|
                          feature}
	    Every wrapped line will continue visually indented (same amount of
	    space as the beginning of that line), thus preserving horizontal blocks
	    of text.

'breakindentopt' 'briopt' string (default empty)
			              local to window
			              {not in Vi}
			              {not available when compiled without the |+linebreak|
                          feature}
	    Settings for 'breakindent'. It can consist of the following optional
	    items and must be seperated by a comma:
		          min:{n}	  Minimum text width that will be kept after
			                  applying 'breakindent', even if the resulting
			                  text should normally be narrower. This prevents
			                  text indented almost to the right window border
			                  occupying lot of vertical space when broken.
		          shift:{n}   After applying 'breakindent', wrapped line
			                  beginning will be shift by given number of
			                  characters. It permits dynamic French paragraph
			                  indentation (negative) or emphasizing the line
			                  continuation (positive).
		          sbr	      Display the 'showbreak' value before applying the 
			                  additional indent.
	    The default value for min is 20 and shift is 0.

Also relevant to this is the showbreak setting, this will suffix your shift amount with character(s) you specify.

Example configuration

" enable indentation
set breakindent

" ident by an additional 2 characters on wrapped lines, when line >= 40 characters, put 'showbreak' at start of line
set breakindentopt=shift:2,min:40,sbr

" append '>>' to indent
set showbreak=>>   

Note on behaviour

If you don't specify the sbr option, any showbreak any characters put appended to the indentation. Removing sbr from the above example causes an effective indent of 4 characters; with that setting, if you just want to use showbreak without additional indentation, specify shift:0.

You can also give a negative shift, which would have the effect of dragging showbreak characters, and wrapped text, back into any available indent space.

When specifying a min value, the shifted amount will be squashed if you terminal width is narrower, but showbreak characters are always preserved.

Solution 2 - Vim

There is a patch for this, but it's been lingering for years and last time I checked did not apply cleanly. See the "Correctly indent wrapped lines" entry in http://groups.google.com/group/vim_dev/web/vim-patches -- I really wish this would get in the mainline.

Update: that link seems to have bitrotted. Here is a more up to date version of the patch.

Update 2: it has been merged upstream (as of 7.4.345), so now you only have to :set breakindent.

Solution 3 - Vim

I don't think it's possible to have exactly the same indentation, but you can still get a better view by setting the 'showbreak' option.

:set showbreak=>>>

Example:

<p>
    <a href="http://www.example.com">
        This is a bogus link, used to demonstrate
>>>an example
    </a>
</p>

The real thing looks better than the example code above, because Vim uses a different colour for '>>>'.

Solution 4 - Vim

UPDATE: In June 2014, a patch to support a breakindent option was merged into Vim (version 7.4.346 or later for best support).


You might also try :set nowrap which will allow vim to display long lines by scrolling to the right. This may be useful for examining the overall structure of a document, but can be less convenient for actually editing.

Other options close to what you're looking for are linebreak and showbreak. With showbreak, you can modify what is displayed at the left margin of lines that are wrapped, but unfortunately it doesn't allow a variable indent depending on the current context.

Solution 5 - Vim

The only way I know of that you could do this would be to use a return character (as mentioned by Cfreak) and combine the textwidth option with the various indentation options. If your indent is configured correctly (as it is by default with the html syntax I believe, but otherwise see the autoindent and smartindent options), you can:

:set formatoptions = tcqw
:set textwidth = 50
gggqG

If you have any customisation of the formatoptions setting, it may be better to simply do:

:set fo += w
:set tw = 50
gggqG

What this does:

:set fo+=w  " Add the 'w' flag to the formatoptions so 
            " that reformatting is only done when lines
            " end in spaces or are too long (so your <p>
            " isn't moved onto the same line as your <a...).
:set tw=50  " Set the textwidth up to wrap at column 50
gg          " Go to the start of the file
gq{motion}  " Reformat the lines that {motion} moves over.
G           " Motion that goes to the end of the file.

Note that this is not the same as a soft wrap: it will wrap the lines in the source file as well as on the screen (unless you don't save it of course!). There are other settings that can be added to formatoptions that will auto-format as you type: details in :help fo-table.

For more information, see:

:help 'formatoptions'
:help fo-table
:help 'textwidth'
:help gq
:help gg
:help G
:help 'autoindent'
:help 'smartindent'

Solution 6 - Vim

:set smartindent
:set autoindent

I think you still have to use a return though

Solution 7 - Vim

If your HTML is sufficiently well formed, running it through xmllint might help:

:%!xmllint --html --format

Solution 8 - Vim

A Macro Solution:


Edit:

The operate gq{motion} auto-formats to whatever the variable "textwidth" is set to. This is easier/better than using the 80lBi^M I have for my macro.


If you have autoindent enabled

:set autoindent

Then entering a return at the end of a line will indent the next line the same amount. You can use this to hard enter in linewraps if you'd like. The following macro takes advantage of this to automatically indent your text:

set register z to:

gg/\v^.{80,}$^M@x (change 80 to whatever length you want your text to be)

and set register x to:

80lBi^M^[n@x (change 80 to whatever length you want your text to be)

Then do

@x   

to activate the macros. After a few seconds you're text will all be in properly indented lines of 80 characters or less.

Explanation:

Here's a dissection of the macros:

Part 1 (macro z):

gg/\v^.{80,}$^M@x

gg - start at the top of the file (this avoids some formatting issues)
/  - begin search
\v - switch search mode to use a more generic regex input style - no weird vim 'magic'
^.{80,}$ - regex for lines that contain 80 or more characters
^M - enter - do the search (don't type this, you can enter it with ctrl+v then enter)
@x - do macro x

Part 2 (macro x):

80lBi^M^[n@x

80l - move right 80 characters
B   - move back one WORD (WORDS include characters like "[];:" etc.)
i^M - enter insert mode and then add a return (again don't type this, use ctrl+v)
^[  - escape out of insert mode (enter this with ctrl+v then escape)
@x  - repeat the macro (macro will run until there are no more lines of 80 characters or more)

Caveats:

  • This macro will break if the there's a WORD that is 80 characters or longer.

  • This macro will not do smart things like indent lines past tags.

  • Use the lazyredraw setting (:set lazyredraw) to speed this up

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSashaView Question on Stackoverflow
Solution 1 - VimDominykas MostauskisView Answer on Stackoverflow
Solution 2 - VimergosysView Answer on Stackoverflow
Solution 3 - Vimtoo much phpView Answer on Stackoverflow
Solution 4 - VimGreg HewgillView Answer on Stackoverflow
Solution 5 - VimDrAlView Answer on Stackoverflow
Solution 6 - VimCfreakView Answer on Stackoverflow
Solution 7 - VimArkadyView Answer on Stackoverflow
Solution 8 - VimMichael AsnesView Answer on Stackoverflow