Fixing too long comment lines in Vim - vim

I'm looking for a convenient way to fix comments where line lengths exceed a certain number of characters in Vim. I'm fine with doing this manually with code, especially since it's not that frequent, plus refactoring long lines is often language, or even code-style dependent, but with comments this is pure drudgery.
What happens is I often spot some issue in a comment, tweak one or two words and the line spills out of the, say, 80 character limit. I move the last word to the next line and then the next line spills, and so on. Does anyone know a way to do this automatically in Vim?

I would recommend putting the following into your vimrc if this is a regular issue:
nnoremap <leader>f gqip
This maps the leader f shortcut (f is for "format") to format the comment (considered a paragraph after setting some formatoption flags) with gq which formats the comment to be the width of the currently set textwidth or tw option. You should set textwidth in your .vimrc with textwidth=80.
Formatoptions is the other thing you should fiddle with, specifically in your case by adding the acq flags with formatoptions+=acq. Be careful to remove the t flag with formatoptions-=t because that will automatically wrap all of your code, not just recognized comments. After doing all this you should be able to hit f and format inside only the comment, irrespective of whether is is surrounded by blank lines.
Here is the relevant info on formatoptions so you can make your own choices.
t Auto-wrap text using textwidth
c Auto-wrap comments using textwidth, inserting the current comment
leader automatically.
r Automatically insert the current comment leader after hitting
<Enter> in Insert mode.
o Automatically insert the current comment leader after hitting 'o' or
'O' in Normal mode.
q Allow formatting of comments with "gq".
Note that formatting will not change blank lines or lines containing
only the comment leader. A new paragraph starts after such a line,
or when the comment leader changes.
w Trailing white space indicates a paragraph continues in the next line.
A line that ends in a non-white character ends a paragraph.
a Automatic formatting of paragraphs. Every time text is inserted or
deleted the paragraph will be reformatted. See |auto-format|.
When the 'c' flag is present this only happens for recognized
comments.

Related

Limit the number of characters per line editor vi linux

I am trying that in the editor vi, limit the number of characters per line you can do. Once you reach those x characters, break the line with a carriage return. For example: limit 50 characters.
I have not seen that there is any command (like :set nu to write the numbers of the lines in editor vi) or something similar to activate it.
I know that in order for it to take effect I have to create the file ~/.vimrc but there I don't know how to edit it so that when I later create a file, I restrict it.
Are you really using vi? You are probably using vim. If so, :help will answer most of your _I don't know_s. From there, you can also jump to specific parts of the help following the links (you recognize them as they are likely colored, bolded, or highligthed somehow) by hitting Ctrl+] (and yes, you can also enter :help ctrl-] to see the help on the key combination I've just mentioned).
In order to do what you want, it is enough that you put set textwidth=50 or set tw=50 in your ~/.vimrc file (note that a value of zero for tw means that the option is disabled, or if you prefer, that tw is infinite). If you want to look at the description of this option, enter :help textwidth.
This setting (:set tw=50), however, won't change already existing lines; in order to change all the already existing lines according to the current setting of tw, you can do gggqG, which moves to the first line (gg) and then formats the lines (gq, for info enter :help gq, which will also reveal the reason why this command will have an effect even if tw is 0) till to the last line (G moves to last line of file).

vim: end comments and retain indentation

I'd like to be able to end a run of comments but retain the current indentation. Is this possible either through an existing command or with a function?
I have formatoptions -=o and autoindent so I normally get by using o from normal mode - the cursor is on the next line, the indentation is correct and I'm in insert mode. I'm only worrying about single line comments (eg '#'s - as for shell, python etc).
I'm interested in how I can make this more general (particularly not dependent on my formatoptions). I'd like to have an imap for ;; but I can't seem to find a straight forward way if I want to call a function (for example, to check whether I'm currently on a comment line).
I've played around with <expr> mappings and the expression register but either I lose the indentation (cursor ends up in the first column) or the comment continues. It seems like there might be a better alternative to either reimplementing the autoindent logic or trying to delete the extra comment characters. I've also tried saving/restoring formatoptions while using normal o but leaving insert mode when there's no other content on the line deletes the indentation.
I appreciate suggestions about how I should approach this.

How to keep my own CR in Vim with automatic format?

I used set fo+=a in Vim to enable automatic format when typing.
With that set, the <CR> I pressed will be erased when I continue to type, if the length of current line is less than lw, and that is not what I want.
What I want is:
Still able to add a <CR> automatically if the line is longer than lw.
When I type a <CR> manually when the line length is less than lw, I don't want that <CR> erased when I continue to type.
Thanks.
You can't. The format option "a" is designed to reformat your paragraph every time your paragraph is changed, so there's no way for you to keep any single line breaks inside your paragraph, regarding the definition of "paragraph" in VIM.
If you only need to be able to wrap long lines while typing, you don't need option "a". Option "t" is already quite sufficient for your case.
t Auto-wrap text using textwidth
If you are fine with using trailing spaces to indicate that a paragraph continues (by default it only ends on an empty line) then you can also do
set fo+=w
. Then to keep vim from joining lines all you need is to end it with something other then a space.
Note: this is not going to change the meaning of the paragraph for motion commands (in fact, there is nothing that can do change it).

Vim: Smart indent when entering insert mode on blank line?

When I open a new line (via 'o') my cursor jumps to a correctly indented position on the next line. On the other hand, entering insert mode while my cursor is on a blank line doesn't move my cursor to the correctly indented location.
How do I make vim correctly indent my cursor when entering insert mode (via i) on a blank line?
cc will replace the contents of the current line and enter insert mode at the correct indentation - so on a blank line will do exactly what you're after.
I believe that the behaviour of i you describe is correct because there are many use cases where you want to insert at that specific location on a blank line, rather than jumping to wherever vim guesses you want to insert.
Well this actually wasn't as bad as I thought it would be. One way to enable this is to add the following to your ~/.vimrc
"smart indent when entering insert mode with i on empty lines
function! IndentWithI()
if len(getline('.')) == 0
return "\"_ccO"
else
return "i"
endif
endfunction
nnoremap <expr> i IndentWithI()
It simply checks for an empty line when you hit 'i' from insert mode. If you are indeed on an empty line it will delete it and open a new one, effectively leveraging the working 'open line' behavior.
Note: "_ before the cc makes sure that your register doesn't get wiped
On an empty line, to enter insert mode correctly indented, you can simply use s.
Note that s is a synonym for cl, so if you're not actually on an empty line, it'll end up deleting a single character and not indenting. In that case, you're better off using cc, as sml suggested some 18 months ago. But I've frequently improved my score at VimGolf by using this shortcut, so thought I'd mention it. ;)

Smart Wrap in Vim

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>
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.
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.
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 '>>>'.
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.
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'
:set smartindent
:set autoindent
I think you still have to use a return though
If your HTML is sufficiently well formed, running it through xmllint might help:
:%!xmllint --html --format
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

Resources