Deleting spaces on multiple lines in VIM - vim

To indent HAML code I usually add or delete 2 spaces. Adding I do:
Enter visual mode ( ctrl + v)
jj to select the lines
shift + i to go into insert
type 2 spaces
ESC
That's it 2 spaces are added. However to remove the spaces, I't does not work, for example doing:
Enter visual mode ( ctrl + v)
jj to select the lines
shift + i to go into insert
Delete 2 spaces ( with backspace or delete)
ESC
This just does not work, other lines spaces are not deleted. How then can I do this ?
Here is an example code:
.module_1
.pricing_details
%h2
Save
The idea is moving everything so it matches 2 space in respecto .module_1 as:
.module_1
.pricing_details
%h2
Save
The propose solution using < > works only for indenting now I'd like to for example:
.module_1
.pricing_details
%h2
Save
move the above to:
.module_1
.pricing_details
%h2
Save

Try < and > commands. You will need :set shiftwidth=2 for them to work in this way.
UPDATE
Considering your last example, changing
.module_1
.pricing_details
%h2
Save
to ⇓
.module_1
.pricing_details
%h2
Save
can be accomplished with moving to .pricing_details line and hitting Vjj<.

Highlight your text and do:
<
Use:
.
To repeat the action multiple times. Note that this will shift the text whatever your shift width is. If it is not 2, you can set it to 2 by doing:
:set sw=2
You can indent text the same way by using ">".
All of this is in the documentation: http://vimdoc.sourceforge.net/htmldoc/usr_25.html#25.3

in the vimrc:
" pressing F5 adds two spaces at beginning of line and goes to next line
inoremap <F5> <ESC>:s/\(.*\)/ \1/e<CR>:set nohlsearch<CR>ji
" also works when not in edit mode
map <F5> i<F5><ESC>
" F6 removes two spaces from the end of whitespace at the beginning of line
inoremap <F6> <ESC>:s/\(^\s*\)/\1/e<CR>:set nohlsearch<CR>ji
map <F6> i<F6><ESC>
To remove 2 spaces from the beginning of every line of a paragraph just press F5 through all its lines.
This is modeled after my keybindings for commenting and uncommenting C code (the difference is in the regex of course)
only drawback is it needs to disable search highlight since the regex matches damn near the entire document all the time.

Related

How to collapse space after cursor in vim

I have my cursor between two lines in vim:
I would do this in a 'normal' editor by pressing ctrl-d to delete the characters after the cursor. What would be the most efficient way to do this in vim?
Your current cursor is at ,:
if you want to remove the linebreak: press J
if you want to remove the ',' : press x
if you want to remove the closing single-quote ': press X
If you want to join lines with no space in beewin them press
gJ
If you want to remove the rest of the line in insert mode:
Ctrl-o D
To map this action, you can put this on your ~/.vimrc
" delete the rest of the current line
inoremap <c-k> <c-o>d
I'm not suggesting maping Ctrld because it is already mapped to decrease indenting, in oposition to Ctrlt

Need script/function/command to surround text with other text

I'm new to scripting in Vim. I need to write a script that surrounds a piece of text with other text. For example:
\surroundingtext{surrounded text}
(yes it is for LaTeX). I want to either highlight "surrounded text" and issue the command, or have "surrounded text" the result of a regular expression command.
I guess the question is, how to put this in a function?
Thanks,
Jeremy
Here's what I do:
vnoremap <buffer> <leader>sur "zc\surroundingtext{<C-R>z}<Esc>
This creates a visual-mode mapping where you can characterwise-visual select (v) the text that you want to surround, type \sur (assuming a default mapleader of \) and the text will be surrounded by the text you specified.
"z specifies register 'z'
c tells vim to change the visually selected text, placing the original text in register 'z'
\surroundingtest is the left-side
<C-R>z tells Vim to paste register 'z'
} is the right-side
<Esc> puts you back in normal-mode
I also take it a step further and create normal-mode and insert-mode mappings as well:
nnoremap <buffer> <leader>sur i\surroundingtext{}<Esc>i
inoremap <buffer> <leader>sur \surroundingtext{}<Esc>i
You could place these mappings in your ~/.vimrc file but they would be mapped for every filetype.
A better place for them would be your ~/.vim/after/ftplugin/tex.vim file so they're only mapped when your filetype is tex. Create the parent directories if they don't already exist.
This assumes that the filetype is correctly set to tex and you have filetype plugins enabled:
filetype plugin on
I asked a very similar question a few weeks ago. How to repeatedly add text on both sides of a word in vim? There are good starting points in the answers.
I would recommend using visual selection since you need to surround arbitrary chunks of text instead of a single word. Enter visual selection mode by pressing v, then select the text you wish to surround. Next record a macro with the desired modification using the following key strokes:
qa " record a macro in buffer a
x " cut the selected text
i " enter insert mode
prefix " type the desired prefix
<esc> " exit insert mode
p " paste the cut text
a " enter insert mode after the pasted text
postfix " type the desired postfix
<esc> " exit insert mode
q " stop recording
To reuse the macro simply visually select the next block you would like to modify and press #a.
This may be too cumbersome if the surrounding text varies frequently, or if you want this to persist across editing sessions. In that case you would probably want to write a vim script function to handle it in a more robust way.

What's a quick way to comment/uncomment lines in Vim?

I have a Ruby code file open in vi, there are lines commented out with #:
class Search < ActiveRecord::Migration
def self.up
# create_table :searches do |t|
# t.integer :user_id
# t.string :name
# t.string :all_of
# t.string :any_of
# t.string :none_of
# t.string :exact_phrase
#
# t.timestamps
# end
end
def self.down
# drop_table :searches
end
end
Say I want to uncomment all the lines in the first def ... end section. What's an efficient way to do that in Vim?
In general, I'm looking for an easy and fluid way to comment and uncomment lines. Here I'm dealing with Ruby code, but it could be JavaScript (//) or Haml (-#).
For those tasks I use most of the time block selection.
Put your cursor on the first # character, press CtrlV (or CtrlQ for gVim), and go down until the last commented line and press x, that will delete all the # characters vertically.
For commenting a block of text is almost the same:
First, go to the first line you want to comment, press CtrlV. This will put the editor in the VISUAL BLOCK mode.
Then using the arrow key and select until the last line
Now press ShiftI, which will put the editor in INSERT mode and then press #. This will add a hash to the first line.
Then press Esc (give it a second), and it will insert a # character on all other selected lines.
For the stripped-down version of vim shipped with debian/ubuntu by default, type : s/^/# in the third step instead (any remaining highlighting of the first character of each line can be removed with :nohl).
Here are two small screen recordings for visual reference.
Comment:
Uncomment:
To comment out blocks in vim:
press Esc (to leave editing or other mode)
hit ctrl+v (visual block mode)
use the ↑/↓ arrow keys to select lines you want (it won't highlight everything - it's OK!)
Shift+i (capital I)
insert the text you want, e.g. %
press EscEsc
To uncomment blocks in vim:
press Esc (to leave editing or other mode)
hit ctrl+v (visual block mode)
use the ↑/↓ arrow keys to select the lines to uncomment.
If you want to select multiple characters, use one or combine these methods:
use the left/right arrow keys to select more text
to select chunks of text use shift + ←/→ arrow key
you can repeatedly push the delete keys below, like a regular delete button
press d or x to delete characters, repeatedly if necessary
Sometimes I'm shelled into a remote box where my plugins and .vimrc cannot help me, or sometimes NerdCommenter gets it wrong (eg JavaScript embedded inside HTML).
In these cases a low-tech alternative is the built-in norm command, which just runs any arbitrary vim commands at each line in your specified range. For example:
Commenting with #:
1. visually select the text rows (using V as usual)
2. :norm i#
This inserts "#" at the start of each line. Note that when you type : the range will be filled in, so it will really look like :'<,'>norm i#
Uncommenting #:
1. visually select the text as before (or type gv to re-select the previous selection)
2. :norm x
This deletes the first character of each line. If I had used a 2-char comment such as // then I'd simply do :norm xx to delete both chars.
If the comments are indented as in the OP's question, then you can anchor your deletion like this:
:norm ^x
which means "go to the first non-space character, then delete one character". Note that unlike block selection, this technique works even if the comments have uneven indentation!
Note: Since norm is literally just executing regular vim commands, you're not limited to comments, you could also do some complex editing to each line. If you need the escape character as part of your command sequence, type ctrl-v then hit the escape key (or even easier, just record a quick macro and then use norm to execute that macro on each line).
Note 2: You could of course also add a mapping if you find yourself using norm a lot. Eg putting the following line in ~/.vimrc lets you type ctrl-n instead of :norm after making your visual selection
vnoremap <C-n> :norm
Note 3: Bare-bones vim sometimes doesn't have the norm command compiled into it, so be sure to use the beefed up version, ie typically /usr/bin/vim, not /bin/vi
(Thanks to #Manbroski and #rakslice for improvements incorporated into this answer)
I use the NERD Commenter script. It lets you easily comment, uncomment or toggle comments in your code.
As mentioned in the comments:
for anyone who is confused by the usage, default leader is "\" so 10\cc will comment ten lines and 10\cu will uncomment those ten lines
I have the following in my .vimrc:
" Commenting blocks of code.
augroup commenting_blocks_of_code
autocmd!
autocmd FileType c,cpp,java,scala let b:comment_leader = '// '
autocmd FileType sh,ruby,python let b:comment_leader = '# '
autocmd FileType conf,fstab let b:comment_leader = '# '
autocmd FileType tex let b:comment_leader = '% '
autocmd FileType mail let b:comment_leader = '> '
autocmd FileType vim let b:comment_leader = '" '
augroup END
noremap <silent> ,cc :<C-B>silent <C-E>s/^/<C-R>=escape(b:comment_leader,'\/')<CR>/<CR>:nohlsearch<CR>
noremap <silent> ,cu :<C-B>silent <C-E>s/^\V<C-R>=escape(b:comment_leader,'\/')<CR>//e<CR>:nohlsearch<CR>
Now you can type ,cc to comment a line and ,cu to uncomment a line (works both in normal and visual mode).
(I stole it from some website many years ago so I can't completely explain how it works anymore :). There is a comment where it is explained.)
Specify which lines to comment in vim:
Reveal the line numbers:
:set number
then
:5,17s/^/#/ this will comment out line 5-17
or this:
:%s/^/#/ will comment out all lines in file
Here is how I do it:
Go to first character on the first line you want to comment out.
Hit Ctrl+q in GVIM or Ctrl+v in VIM, then go down to select first character on the lines to comment out.
Then press c, and add the comment character.
Uncommenting works the same way, just type a space instead of the comment character.
Toggle comments
If all you need is toggle comments I'd rather go with commentary.vim by tpope.
Installation
Pathogen:
cd ~/.vim/bundle
git clone git://github.com/tpope/vim-commentary.git
vim-plug:
Plug 'tpope/vim-commentary'
Vundle:
Plugin 'tpope/vim-commentary'
Further customization
Add this to your .vimrc file: noremap <leader>/ :Commentary<cr>
You can now toggle comments by pressing Leader+/, just like Sublime and Atom.
I've come up with a simple addition to my .vimrc file which works pretty well and can be extended easily. You simply add a new filetype to the comment_map and its comment leader.
I added a mapping to normal and visual modes, but you can remap to anything you like. I prefer only to have a 'toggle' style function. One bears having multiple mappings etc.
let s:comment_map = {
\ "c": '\/\/',
\ "cpp": '\/\/',
\ "go": '\/\/',
\ "java": '\/\/',
\ "javascript": '\/\/',
\ "lua": '--',
\ "scala": '\/\/',
\ "php": '\/\/',
\ "python": '#',
\ "ruby": '#',
\ "rust": '\/\/',
\ "sh": '#',
\ "desktop": '#',
\ "fstab": '#',
\ "conf": '#',
\ "profile": '#',
\ "bashrc": '#',
\ "bash_profile": '#',
\ "mail": '>',
\ "eml": '>',
\ "bat": 'REM',
\ "ahk": ';',
\ "vim": '"',
\ "tex": '%',
\ }
function! ToggleComment()
if has_key(s:comment_map, &filetype)
let comment_leader = s:comment_map[&filetype]
if getline('.') =~ "^\\s*" . comment_leader . " "
" Uncomment the line
execute "silent s/^\\(\\s*\\)" . comment_leader . " /\\1/"
else
if getline('.') =~ "^\\s*" . comment_leader
" Uncomment the line
execute "silent s/^\\(\\s*\\)" . comment_leader . "/\\1/"
else
" Comment the line
execute "silent s/^\\(\\s*\\)/\\1" . comment_leader . " /"
end
end
else
echo "No comment leader found for filetype"
end
endfunction
nnoremap <leader><Space> :call ToggleComment()<cr>
vnoremap <leader><Space> :call ToggleComment()<cr>
Note:
I don't use any callbacks or hooks into the file types/loading, because I find they slow down Vim's startup more than the .vimrc static function/map does but that's just my preference. I've also tried to keep it simple and performant. If you do use autocommands you need to be sure to put them in an autocommand group or else the callbacks get added to the filetype multiple times per-file loaded and cause a lot of performance degradation.
Use Control-V to select rectangles of text: go to the first # character, type Ctrl+V, move right once, and then down, up to the end of the comments. Now type x: you're deleting all the # characters followed by one space.
Here is a section of my .vimrc:
"insert and remove comments in visual and normal mode
vmap ,ic :s/^/#/g<CR>:let #/ = ""<CR>
map ,ic :s/^/#/g<CR>:let #/ = ""<CR>
vmap ,rc :s/^#//g<CR>:let #/ = ""<CR>
map ,rc :s/^#//g<CR>:let #/ = ""<CR>
In normal and in visual mode, this lets me press ,ic to insert comments and,rc to remove comments.
I use vim 7.4 and this works for me.
Assuming we are commenting/uncommenting 3 lines.
To comment:
if the line has no tab/space at the beginning:
ctrl + V then jjj then shift + I (cappital i) then //then esc esc
if the line has tab/space at the beginning you still can do the above or swap for c:
ctrl + V then jjj then c then //then esc esc
To uncomment:
if the lines have no tab/space at the beginning:
ctrl + V then jjj then ll (lower cap L) then c
if the lines have tab/space at the beginning, then you space one over and esc
ctrl + V then jjj then ll (lower cap L) then c then space then esc
I combined Phil and jqno's answer and made untoggle comments with spaces:
autocmd FileType c,cpp,java,scala let b:comment_leader = '//'
autocmd FileType sh,ruby,python let b:comment_leader = '#'
autocmd FileType conf,fstab let b:comment_leader = '#'
autocmd FileType tex let b:comment_leader = '%'
autocmd FileType mail let b:comment_leader = '>'
autocmd FileType vim let b:comment_leader = '"'
function! CommentToggle()
execute ':silent! s/\([^ ]\)/' . escape(b:comment_leader,'\/') . ' \1/'
execute ':silent! s/^\( *\)' . escape(b:comment_leader,'\/') . ' \?' . escape(b:comment_leader,'\/') . ' \?/\1/'
endfunction
map <F7> :call CommentToggle()<CR>
how it works:
Lets assume we work with #-comments.
The first command s/\([^ ]\)/# \1/ searches for the first non-space character [^ ] and replaces that with # +itself. The itself-replacement is done by the \(..\) in the search-pattern and \1 in the replacement-pattern.
The second command s/^\( *\)# \?# \?/\1/ searches for lines starting with a double comment ^\( *\)# \?# \? (accepting 0 or 1 spaces in between comments) and replaces those simply with the non-comment part \( *\) (meaning the same number of preceeding spaces).
For more details about vim patterns check this out.
Visual and Shift-I did not worked for me.
Simplest that worked without any plugins is
Select block - V then j or k or any relevant motion (Don't use arrow keys) :)
Then hit : it prompts command to :'<,'>
To Comment
Using # - `s/^/#/`
Using `//` - `s/^/\/\//`
To Uncomment
Using # - `s/^#//`
Using `//` - `s/^\/\//`
Exaplanation -
'<,'> - Apply to visual block
s - substitute
^ - starts with
after / add character # in this case of \/\/ escaped for //
Update
I wrote a function to comment and uncomment current line with <Space><Space>
Works for next 10 lines for example 10<Space><Space>
Paste it to .vimrc
function CommentUncomment()
let line = getline('.')
if line[:1] == "//"
norm ^2x
else
norm I//
endif
endfunction
nnoremap <Space><Space> :call CommentUncomment()<CR>
If you already know the line numbers, then n,ms/# // would work.
With 30 answers ahead of me, I'll try to give an even easier solution: Insert a # at the beginning of the line. Then go down a line and press dot (.). To repeat, do j,.,j,., etc...To uncomment, remove a # (you can hit x over the #), and do the reverse using k,.,etc...
How to uncomment the following three lines in vi:
#code code
#code
#code code code
Place the cursor over the upper left # symbol and press CtrlV. This puts you in visual block mode. Press the down arrow or J three times to select all three lines. Then press D. All the comments disappear. To undo, press U.
How to comment the following three lines in vi:
code code
code
code code code
Place the cursor over the upper left character, press CtrlV. This puts you in visual block mode. Press ↓ or J three times to select all three lines. Then press:
I//Esc
That's a capital I, //, and Escape.
When you press ESC, all the selected lines will get the comment symbol you specified.
I like to use the tcomment plugin:
http://www.vim.org/scripts/script.php?script_id=1173
I have mapped gc and gcc to comment a line or a highlighted block of code. It detects the file type and works really well.
Yes, there are 33 (mostly repetitive) answers already to this question.
Here is another approach to how to comment lines out in Vim: motions. The basic idea is to comment or uncomment lines out using the same method as yanking a paragraph by typing yip or deleting 2 lines by typing dj.
This approach will let you do things like:
ccj to comment the next 2 lines out, and cuk to uncomment them;
cci{ to comment a block out, and cui{ to uncomment it;
ccip to comment a whole paragraph out, and cuip to uncomment it.
ccG to comment everything out down to the last line, and cugg to uncomment everything up to the first line.
All you need are 2 functions that operate over motions, and 2 mappings for each function. First, the mappings:
nnoremap <silent> cc :set opfunc=CommentOut<cr>g#
vnoremap <silent> cc :<c-u>call CommentOut(visualmode(), 1)<cr>
nnoremap <silent> cu :set opfunc=Uncomment<cr>g#
vnoremap <silent> cu :<c-u>call Uncomment(visualmode(), 1)<cr>
(See the manual about the g# operator and the operatorfunc variable.)
And now the functions:
function! CommentOut(type, ...)
if a:0
silent exe "normal! :'<,'>s/^/#/\<cr>`<"
else
silent exe "normal! :'[,']s/^/#/\<cr>'["
endif
endfunction
function! Uncomment(type, ...)
if a:0
silent exe "normal! :'<,'>s/^\\(\\s*\\)#/\\1/\<cr>`<"
else
silent exe "normal! :'[,']s/^\\(\\s*\\)#/\\1/\<cr>`["
endif
endfunction
Modify the regular expressions above to suit your taste as to where the # should be:
There is this life changing plugin by tpope called vim-commentary
https://github.com/tpope/vim-commentary
This plugin provides:
Sanity
Properly indented comments
Does not comment out empty/unnecessary lines
Usage:
Install via Vundle (or Pathogen I guess).
Highlight your text and press : which will show as :<,'>
Type Commentary here :<,'>Commentary and press Enter.
Boom. Your done bud.
I mark the first and last lines (ma and mb), and then do :'a,'bs/^# //
A few regular Vim commands do not work with my setup on Windows. Ctrl + v and Ctrl + q are some of them. I later discovered the following methods worked to uncomment lines.
Given
Some indented comments
# Practice in Vim
# Practice in Vim
# Practice in Vim
# Practice in Vim
# Practice in Vim
# Practice in Vim
# Practice in Vim
The following approaches remove the # symbol and preserve indents.
Approaches
Move the cursor to the first comment (arrows or h, j, k, l). Then apply one of the following techniques:
Visual Block Mode (faster)
Ctrl + Shift + v to enter visual block mode
js to choose the vertical lines.
l to include horizontal characters (optional)
x to delete the block
Search/Replace + Regex
Choose text with regular visual mode, i.e. Shift + v
Type :. You'll get this prompt '<,'>.
Type regex, e.g. s/#// substitutes the hash with nothing.
(Optional: type s/# // to include the space).
Enter
:norm command
Choose text with regular visual mode, i.e. Shift + v
Type :. You'll get this prompt '<,'>.
Give a command. Type :norm ^x to remove the first non-whitespace character and the next character. (Optional: try :norm x if not indented or :norm ^xx to include the space).
Enter
g mode
Choose text with regular visual mode, i.e. Shift + v
Type :. You'll get this prompt '<,'>.
Give a command. Type g/#/norm! ^x.
(Optional: type g/#/norm! ^xx to include the space).
Enter
Results
Practice in Vim
Practice in Vim
Practice in Vim
Practice in Vim
Practice in Vim
Practice in Vim
Practice in Vim
See Also
Post on removing indented comments
Post on how to quickly comment w/Vim
ThePrimeagen's tutorial on g commands.
VimTrick's tutorial on Commenting code
I use EnhancedCommentify. It comments everything I needed (programming languages, scripts, config files). I use it with visual-mode bindings. Simply select text you want to comment and press co/cc/cd.
vmap co :call EnhancedCommentify('','guess')<CR>
vmap cc :call EnhancedCommentify('','comment')<CR>
vmap cd :call EnhancedCommentify('','decomment')<CR>
This answer is most useful if you are unable to install plugins but you still want your comment characters to follow existing indentation levels.
This answer is here to 1) show the correct code to paste into a .vimrc to get vim 7.4+ to do block commenting/uncommenting while keeping indentation level with 1 shortcut in visual mode and 2) to explain it.
Here is the code:
let b:commentChar='//'
autocmd BufNewFile,BufReadPost *.[ch] let b:commentChar='//'
autocmd BufNewFile,BufReadPost *.cpp let b:commentChar='//'
autocmd BufNewFile,BufReadPost *.py let b:commentChar='#'
autocmd BufNewFile,BufReadPost *.*sh let b:commentChar='#'
function! Docomment ()
"make comments on all the lines we've grabbed
execute '''<,''>s/^\s*/&'.escape(b:commentChar, '\/').' /e'
endfunction
function! Uncomment ()
"uncomment on all our lines
execute '''<,''>s/\v(^\s*)'.escape(b:commentChar, '\/').'\v\s*/\1/e'
endfunction
function! Comment ()
"does the first line begin with a comment?
let l:line=getpos("'<")[1]
"if there's a match
if match(getline(l:line), '^\s*'.b:commentChar)>-1
call Uncomment()
else
call Docomment()
endif
endfunction
vnoremap <silent> <C-r> :<C-u>call Comment()<cr><cr>
How it works:
let b:commentChar='//' : This creates a variable in vim. the b here refers to the scope, which in this case is contained to the buffer, meaning the currently opened file. Your comment characters are strings and need to be wrapped in quotes, the quotes are not part of what will be substituted in when toggling comments.
autocmd BufNewFile,BufReadPost *... : Autocommands trigger on different things, in this case, these are triggering when a new file or the read file ends with a certain extension. Once triggered, the execute the following command, which allows us to change the commentChar depending on filetype. There are other ways to do this, but they are more confusing to novices (like me).
function! Docomment() : Functions are declared by starting with function and ending with endfunction. Functions must start with a capital. the ! ensures that this function overwrites any previous functions defined as Docomment() with this version of Docomment(). Without the !, I had errors, but that might be because I was defining new functions through the vim command line.
execute '''<,''>s/^\s*/&'.escape(b:commentChar, '\/').' /e' : Execute calls a command. In this case, we are executing substitute, which can take a range (by default this is the current line) such as % for the whole buffer or '<,'> for the highlighted section. ^\s* is regex to match the start of a line followed by any amount of whitespace, which is then appended to (due to &). The . here is used for string concatenation, since escape() can't be wrapped in quotes. escape() allows you to escape character in commentChar that matches the arguments (in this case, \ and /) by prepending them with a \. After this, we concatenate again with the end of our substitute string, which has the e flag. This flag lets us fail silently, meaning that if we do not find a match on a given line, we won't yell about it. As a whole, this line lets us put a comment character followed by a space just before the first text, meaning we keep our indentation level.
execute '''<,''>s/\v(^\s*)'.escape(b:commentChar, '\/').'\v\s*/\1/e' : This is similar to our last huge long command. Unique to this one, we have \v, which makes sure that we don't have to escape our (), and 1, which refers to the group we made with our (). Basically, we're matching a line that starts with any amount of whitespace and then our comment character followed by any amount of whitespace, and we are only keeping the first set of whitespace. Again, e lets us fail silently if we don't have a comment character on that line.
let l:line=getpos("'<")[1] : this sets a variable much like we did with our comment character, but l refers to the local scope (local to this function). getpos() gets the position of, in this case, the start of our highlighting, and the [1] means we only care about the line number, not other things like the column number.
if match(getline(l:line), '^\s*'.b:commentChar)>-1 : you know how if works. match() checks if the first thing contains the second thing, so we grab the line that we started our highlighting on, and check if it starts with whitespace followed by our comment character. match() returns the index where this is true, and -1 if no matches were found. Since if evaluates all nonzero numbers to be true, we have to compare our output to see if it's greater than -1. Comparison in vim returns 0 if false and 1 if true, which is what if wants to see to evaluate correctly.
vnoremap <silent> <C-r> :<C-u>call Comment()<cr><cr> : vnoremap means map the following command in visual mode, but don't map it recursively (meaning don't change any other commands that might use in other ways). Basically, if you're a vim novice, always use noremap to make sure you don't break things. <silent> means "I don't want your words, just your actions" and tells it not to print anything to the command line. <C-r> is the thing we're mapping, which is ctrl+r in this case (note that you can still use C-r normally for "redo" in normal mode with this mapping). C-u is kinda confusing, but basically it makes sure you don't lose track of your visual highlighting (according to this answer it makes your command start with '<,'> which is what we want). call here just tells vim to execute the function we named, and <cr> refers to hitting the enter button. We have to hit it once to actually call the function (otherwise we've just typed call function() on the command line, and we have to hit it again to get our substitutes to go through all the way (not really sure why, but whatever).
Anyway, hopefully this helps. This will take anything highlighted with v, V, or C-v, check if the first line is commented, if yes, try to uncomment all highlighted lines, and if not, add an extra layer of comment characters to each line. This is my desired behavior; I did not just want it to toggle whether each line in the block was commented or not, so it works perfectly for me after asking multiple questions on the subject.
"comment (cc) and uncomment (cu) code
noremap <silent> cc :s,^\(\s*\)[^# \t]\#=,\1# ,e<CR>:nohls<CR>zvj
noremap <silent> cu :s,^\(\s*\)# \s\#!,\1,e<CR>:nohls<CR>zvj
You can comment/uncomment single or multiple lines with #. To do multiple lines, select the lines then type cc/cu shortcut, or type a number then cc/cu, e.g. 7cc will comment 7 lines from the cursor.
I got the orignal code from the person on What's the most elegant way of commenting / uncommenting blocks of ruby code in Vim? and made some small changes (changed shortcut keys, and added a space after the #).
I use Tim Pope's vim-commentary plugin.
You can use vim-commentary by tpope (https://github.com/tpope/vim-commentary) you can use it as following:
Enter visual mode by pressing
'v'
Then press
'j' repeatedly or e.g 4j to select 4 row
Now all you have to do with the selection is enter keys:
'gc'
This will comment out all the selection, to uncomment repead keys:
'gc'
Starting with the ideas in answers here, I started my own comment function.
It toggles comments on and off. It can handle things like //print('blue'); //this thing is blue and just toggles the first comment. Furthermore it adds comments and a single space just where the first non whitespace is and not at the very start of the line.
Aditionally it doesn't unnecessarily copy the whitespaces, but uses zooms (:h \zs for help) to avoid this extra work, when commenting and indented line.
Hope it helps some minimalists out there. Suggestions are welcome.
" these lines are needed for ToggleComment()
autocmd FileType c,cpp,java let b:comment_leader = '//'
autocmd FileType arduino let b:comment_leader = '//'
autocmd FileType sh,ruby,python let b:comment_leader = '#'
autocmd FileType zsh let b:comment_leader = '#'
autocmd FileType conf,fstab let b:comment_leader = '#'
autocmd FileType matlab,tex let b:comment_leader = '%'
autocmd FileType vim let b:comment_leader = '"'
" l:pos --> cursor position
" l:space --> how many spaces we will use b:comment_leader + ' '
function! ToggleComment()
if exists('b:comment_leader')
let l:pos = col('.')
let l:space = ( &ft =~ '\v(c|cpp|java|arduino)' ? '3' : '2' )
if getline('.') =~ '\v(\s*|\t*)' .b:comment_leader
let l:space -= ( getline('.') =~ '\v.*\zs' . b:comment_leader . '(\s+|\t+)#!' ? 1 : 0 )
execute 'silent s,\v^(\s*|\t*)\zs' .b:comment_leader.'[ ]?,,g'
let l:pos -= l:space
else
exec 'normal! 0i' .b:comment_leader .' '
let l:pos += l:space
endif
call cursor(line("."), l:pos)
else
echo 'no comment leader found for filetype'
end
endfunction
nnoremap <Leader>t :call ToggleComment()<CR>
inoremap <Leader>t <C-o>:call ToggleComment()<CR>
xnoremap <Leader>t :'<,'>call ToggleComment()<CR>
This simple snippet is from my .vimrc:
function! CommentToggle()
execute ':silent! s/\([^ ]\)/\/\/ \1/'
execute ':silent! s/^\( *\)\/\/ \/\/ /\1/'
endfunction
map <F7> :call CommentToggle()<CR>
It's for //-Comments, but you can adapt it easily for other characters. You could use autocmd to set a leader as jqno suggested.
This is a very simple and efficient way working with ranges and visual mode naturally.
The quickest and the most intuitive method of them all is to remap ) for walk-down-commenting of lines, and then ( for walk-up-uncommenting. Try it and you won't go back.
In Ruby or Bash, with 2-space indents:
map ) I# <Esc>j
map ( k^2x
In C/C++ or PHP, with 4-space indents:
map ) I// <Esc>j
map ( k^4x
Downsides are that you lose ( and ) for sentence-movement (but das can fill in there), and you'll occasionally fall back on select-and-replace or CtrlV for handling long sections. But that's pretty rare.
And for C-style, the long comments are best handled with:
set cindent
set formatoptions=tcqr
... Which combines well with using V[move]gq to redo the word-wrapping.

Indent multiple lines quickly in vi

It should be trivial, and it might even be in the help, but I can't figure out how to navigate it. How do I indent multiple lines quickly in vi?
Use the > command. To indent five lines, 5>>. To mark a block of lines and indent it, Vjj> to indent three lines (Vim only). To indent a curly-braces block, put your cursor on one of the curly braces and use >% or from anywhere inside block use >iB.
If you’re copying blocks of text around and need to align the indent of a block in its new location, use ]p instead of just p. This aligns the pasted block with the surrounding text.
Also, the shiftwidth setting allows you to control how many spaces to indent.
This answer summarises the other answers and comments of this question, and it adds extra information based on the Vim documentation and the Vim wiki. For conciseness, this answer doesn't distinguish between Vi and Vim-specific commands.
In the commands below, "re-indent" means "indent lines according to your indentation settings." shiftwidth is the primary variable that controls indentation.
General Commands
>> Indent line by shiftwidth spaces
<< De-indent line by shiftwidth spaces
5>> Indent 5 lines
5== Re-indent 5 lines
>% Increase indent of a braced or bracketed block (place cursor on brace first)
=% Reindent a braced or bracketed block (cursor on brace)
<% Decrease indent of a braced or bracketed block (cursor on brace)
]p Paste text, aligning indentation with surroundings
=i{ Re-indent the 'inner block', i.e. the contents of the block
=a{ Re-indent 'a block', i.e. block and containing braces
=2a{ Re-indent '2 blocks', i.e. this block and containing block
>i{ Increase inner block indent
<i{ Decrease inner block indent
You can replace { with } or B, e.g. =iB is a valid block indent command. Take a look at "Indent a Code Block" for a nice example to try these commands out on.
Also, remember that
. Repeat last command
, so indentation commands can be easily and conveniently repeated.
Re-indenting complete files
Another common situation is requiring indentation to be fixed throughout a source file:
gg=G Re-indent entire buffer
You can extend this idea to multiple files:
" Re-indent all your C source code:
:args *.c
:argdo normal gg=G
:wall
Or multiple buffers:
" Re-indent all open buffers:
:bufdo normal gg=G:wall
In Visual Mode
Vjj> Visually mark and then indent three lines
In insert mode
These commands apply to the current line:
CTRL-t insert indent at start of line
CTRL-d remove indent at start of line
0 CTRL-d remove all indentation from line
Ex commands
These are useful when you want to indent a specific range of lines, without moving your
cursor.
:< and :> Given a range, apply indentation e.g.
:4,8> indent lines 4 to 8, inclusive
Indenting using markers
Another approach is via markers:
ma Mark top of block to indent as marker 'a'
...move cursor to end location
>'a Indent from marker 'a' to current location
Variables that govern indentation
You can set these in your .vimrc file.
set expandtab "Use softtabstop spaces instead of tab characters for indentation
set shiftwidth=4 "Indent by 4 spaces when using >>, <<, == etc.
set softtabstop=4 "Indent by 4 spaces when pressing <TAB>
set autoindent "Keep indentation from previous line
set smartindent "Automatically inserts indentation in some cases
set cindent "Like smartindent, but stricter and more customisable
Vim has intelligent indentation based on filetype. Try adding this to your .vimrc:
if has ("autocmd")
" File type detection. Indent based on filetype. Recommended.
filetype plugin indent on
endif
References
Indent a code block
Shifting blocks visually
Indenting source code
:help =
A big selection would be:
gg=G
It is really fast, and everything gets indented ;-)
Also try this for C-indenting indentation. Do :help = for more information:
={
That will auto-indent the current code block you're in.
Or just:
==
to auto-indent the current line.
Key presses for more visual people:
Enter Command Mode:
Escape
Move around to the start of the area to indent:
hjkl↑↓←→
Start a block:
v
Move around to the end of the area to indent:
hjkl↑↓←→
(Optional) Type the number of indentation levels you want
0..9
Execute the indentation on the block:
>
In addition to the answer already given and accepted, it is also possible to place a marker and then indent everything from the current cursor to the marker.
Thus, enter ma where you want the top of your indented block, cursor down as far as you need and then type >'a (note that "a" can be substituted for any valid marker name). This is sometimes easier than 5>> or vjjj>.
The master of all commands is
gg=G
This indents the entire file!
And below are some of the simple and elegant commands used to indent lines quickly in Vim or gVim.
To indent the current line
==
To indent the all the lines below the current line
=G
To indent n lines below the current line
n==
For example, to indent 4 lines below the current line
4==
To indent a block of code, go to one of the braces and use command
=%
These are the simplest, yet powerful commands to indent multiple lines.
When you select a block and use > to indent, it indents then goes back to normal mode. I have this in my .vimrc file:
vnoremap < <gv
vnoremap > >gv
It lets you indent your selection as many time as you want.
Go to the start of the text
press v for visual mode.
use up/down arrow to highlight text.
press = to indent all the lines you highlighted.
As well as the offered solutions, I like to do things a paragraph at a time with >}
Suppose you use 2 spaces to indent your code. Type:
:set shiftwidth=2
Type v (to enter visual block editing mode)
Move the cursor with the arrow keys (or with h/j/k/l) to highlight the lines you want to indent or unindent.
Then:
Type > to indent once (2 spaces).
Type 2> to indent twice (4 spaces).
Type 3> to indent thrice (6 spaces).
...
Type < to unindent once (2 spaces).
Type 2< to unindent twice (4 spaces).
Type 3< to unindent thrice (6 spaces).
...
You get the idea.
(Empty lines will not get indented, which I think is kind of nice.)
I found the answer in the (g)vim documentation for indenting blocks:
:help visual-block
/indent
If you want to give a count to the command, do this just before typing
the operator character: "v{move-around}3>" (move lines 3 indents to
the right).
The beauty of Vim's UI is that its consistency. Editing commands are made up of the command and a cursor move.
The cursor moves are always the same:
H to top of screen, L to bottom, M to middle
nG to go to line n, G alone to bottom of file, gg to top
n to move to next search match, N to previous
} to end of paragraph
% to next matching bracket, either of the parentheses or the tag kind
enter to the next line
'x to mark x where x is a letter or another '.
many more, including w and W for word, $ or 0 to tips of the line, etc., that don't apply here because are not line movements.
So, in order to use vim you have to learn to move the cursor and remember a repertoire of commands like, for example, > to indent (and < to "outdent").
Thus, for indenting the lines from the cursor position to the top of the screen you do >H, >G to indent to the bottom of the file.
If, instead of typing >H, you type dH then you are deleting the same block of lines, cH for replacing it, etc.
Some cursor movements fit better with specific commands. In particular, the % command is handy to indent a whole HTML or XML block. If the file has syntax highlighted (:syn on) then setting the cursor in the text of a tag (like, in the "i" of <div> and entering >% will indent up to the closing </div> tag.
This is how Vim works: one has to remember only the cursor movements and the commands, and how to mix them.
So my answer to this question would be "go to one end of the block of lines you want to indent, and then type the > command and a movement to the other end of the block" if indent is interpreted as shifting the lines, = if indent is interpreted as in pretty-printing.
You can use the norm i command to insert given text at the beginning of the line. To insert 10 spaces before lines 2-10:
:2,10norm 10i
Remember that there has to be a space character at the end of the command - this will be the character we want to have inserted. We can also indent a line with any other text, for example to indent every line in a file with five underscore characters:
:%norm 5i_
Or something even more fancy:
:%norm 2i[ ]
More practical example is commenting Bash/Python/etc code with # character:
:1,20norm i#
To re-indent use x instead of i. For example, to remove first 5 characters from every line:
:%norm 5x
:line_num_start,line_num_end>
For example,
14,21> shifts line number 14 to 21 to one tab
Increase the '>' symbol for more tabs.
For example,
14,21>>> for three tabs
Press "SHIFT + v" to enter VISUAL LINE mode.
Select the text you wish to indent but using either the cursor keys or the "j" and "k" keys.
To indent right press "SHIFT + dot" (> character).
To indent left press "SHIFT + comma" (< character).
Source: https://www.fir3net.com/UNIX/General/how-do-i-tab-multiple-lines-within-vi.html
Do this:
$vi .vimrc
And add this line:
autocmd FileType cpp setlocal expandtab shiftwidth=4 softtabstop=4 cindent
This is only for a cpp file. You can do this for another file type, also just by modifying the filetype...
A quick way to do this using VISUAL MODE uses the same process as commenting a block of code.
This is useful if you would prefer not to change your shiftwidth or use any set directives and is flexible enough to work with TABS or SPACES or any other character.
Position cursor at the beginning on the block
v to switch to -- VISUAL MODE --
Select the text to be indented
Type : to switch to the prompt
Replacing with 3 leading spaces:
:'<,'>s/^/ /g
Or replacing with leading tabs:
:'<,'>s/^/\t/g
Brief Explanation:
'<,'> - Within the Visually Selected Range
s/^/ /g - Insert 3 spaces at the beginning of every line within the whole range
(or)
s/^/\t/g - Insert Tab at the beginning of every line within the whole range
>} or >{ indent from current line up to next paragraph
<} or <{ same un-indent
I like to mark text for indentation:
go to beginning of line of text then type ma (a is the label from the 'm'ark: it could be any letter)
go to end line of text and type mz (again, z could be any letter)
:'a,'z> or :'a,'z< will indent or outdent (is this a word?)
Voila! The text is moved (empty lines remain empty with no spaces)
PS: you can use the :'a,'z technique to mark a range for any operation (d, y, s///, etc.) where you might use lines, numbers, or %.
For me, the MacVim (Visual) solution was, select with mouse and press ">", but after putting the following lines in "~/.vimrc" since I like spaces instead of tabs:
set expandtab
set tabstop=2
set shiftwidth=2
Also it's useful to be able to call MacVim from the command-line (Terminal.app), so since I have the following helper directory "~/bin", where I place a script called "macvim":
#!/usr/bin/env bash
/usr/bin/open -a /Applications/MacPorts/MacVim.app $#
And of course in "~/.bashrc":
export PATH=$PATH:$HOME/bin
MacPorts messes with "~/.profile" a lot, so the PATH environment variable can get quite long.
:help left
In ex mode you can use :left or :le to align lines a specified amount.
Specifically, :left will Left align lines in the [range]. It sets the indent in the lines to [indent] (default 0).
:%le3 or :%le 3 or :%left3 or :%left 3 will align the entire file by padding with three spaces.
:5,7 le 3 will align lines 5 through 7 by padding them with three spaces.
:le without any value or :le 0 will left align with a padding of 0.
This works in Vim and gVim.
5== will indent five lines from the current cursor position.
So you can type any number before ==. It will indent the number of lines. This is in command mode.
gg=G will indent the whole file from top to bottom.
I didn't find a method I use in the comments, so I'll share it (I think Vim only):
Esc to enter command mode
Move to the first character of the last line you want to indent
Ctrl + V to start block select
Move to the first character of the first line you want to indent
Shift + I to enter special insert mode
Type as many space/tabs as you need to indent to (two for example
Press Esc and spaces will appear in all lines
This is useful when you don't want to change indentation/tab settings in vimrc or to remember them to change it while editing.
To unindent I use the same Ctrl + V block select to select spaces and delete it with D.
I don’t know why it's so difficult to find a simple answer like this one...
I myself had to struggle a lot to know this. It's very simple:
Edit your .vimrc file under the home directory.
Add this line
set cindent
in your file where you want to indent properly.
In normal/command mode type
10== (This will indent 10 lines from the current cursor location)
gg=G (Complete file will be properly indented)
I use block-mode visual selection:
Go to the front of the block to move (at the top or bottom).
Press Ctrl + V to enter visual block mode.
Navigate to select a column in front of the lines.
Press I (Shift + I) to enter insert mode.
Type some spaces.
Press Esc. All lines will shift.
This is not a uni-tasker. It works:
In the middle of lines.
To insert any string on all lines.
To change a column (use c instead of I).
yank, delete, substitute, etc...
For a block of code, {}: = + %
For a selected line: Shift + v select using the up/down arrow keys, and then press =.
For the entire file: gg + = + G
Note: 'gg' means go to line 1, '=' is the indent command, and 'G' moves the cursor to the end of file.
For who like modern editors to indent selected line with <TAB> -> Tab and <S-TAB> -> Shift+Tab:
vnoremap <TAB> >gv
vnoremap <S-TAB> <gv
Usage:
Hit V for line-wise visual-mode, select lines you want, then hit Tab(maybe with shift), then indention applies as you want and selection remains...
Using Python a lot, I find myself needing frequently needing to shift blocks by more than one indent. You can do this by using any of the block selection methods, and then just enter the number of indents you wish to jump right before the >
For example, V5j3> will indent five lines three times - which is 12 spaces if you use four spaces for indents.
To indent every line in a file type, Esc and then G=gg.
How to indent highlighted code in vi immediately by a number of spaces:
Option 1: Indent a block of code in vi to three spaces with Visual Block mode:
Select the block of code you want to indent. Do this using Ctrl+V in normal mode and arrowing down to select text. While it is selected, enter : to give a command to the block of selected text.
The following will appear in the command line: :'<,'>
To set indent to three spaces, type le 3 and press enter. This is what appears: :'<,'>le 3
The selected text is immediately indented to three spaces.
Option 2: Indent a block of code in vi to three spaces with Visual Line mode:
Open your file in vi.
Put your cursor over some code
Be in normal mode and press the following keys:
Vjjjj:le 3
Interpretation of what you did:
V means start selecting text.
jjjj arrows down four lines, highlighting four lines.
: tells vi you will enter an instruction for the highlighted text.
le 3 means indent highlighted text three lines.
The selected code is immediately increased or decreased to three spaces indentation.
Option 3: use Visual Block mode and special insert mode to increase indent:
Open your file in vi.
Put your cursor over some code
Be in normal mode press the following keys:
Ctrl+V
jjjj
(press the spacebar five times)
Esc
Shift+i
All the highlighted text is indented an additional five spaces.

How to duplicate a whole line in Vim?

How do I duplicate a whole line in Vim in a similar way to Ctrl+D in IntelliJ IDEA/ Resharper or Ctrl+Alt+↑/↓ in Eclipse?
yy or Y to copy the line (mnemonic: yank)
or
dd to delete the line (Vim copies what you deleted into a clipboard-like "register", like a cut operation)
then
p to paste the copied or deleted text after the current line
or
Shift + P to paste the copied or deleted text before the current line
Normal mode: see other answers.
The Ex way:
:t. will duplicate the line,
:t 7 will copy it after line 7,
:,+t0 will copy current and next line at the beginning of the file (,+ is a synonym for the range .,.+1),
:1,t$ will copy lines from beginning till cursor position to the end (1, is a synonym for the range 1,.).
If you need to move instead of copying, use :m instead of :t.
This can be really powerful if you combine it with :g or :v:
:v/foo/m$ will move all lines not matching the pattern “foo” to the end of the file.
:+,$g/^\s*class\s\+\i\+/t. will copy all subsequent lines of the form class xxx right after the cursor.
Reference: :help range, :help :t, :help :g, :help :m and :help :v
YP or Yp or yyp.
Doesn't get any simpler than this! From normal mode:
yy
then move to the line you want to paste at and
p
yy
will yank the current line without deleting it
dd
will delete the current line
p
will put a line grabbed by either of the previous methods
Do this:
First, yy to copy the current line, and then p to paste.
If you want another way:
"ayy:
This will store the line in buffer a.
"ap:
This will put the contents of buffer a at the cursor.
There are many variations on this.
"a5yy:
This will store the 5 lines in buffer a.
See "Vim help files for more fun.
yyp - remember it with "yippee!"
Multiple lines with a number in between:
y7yp
yyp - paste after
yyP - paste before
I like:
Shift+v (to select the whole line immediately and let you select other lines if you want), y, p
Another option would be to go with:
nmap <C-d> mzyyp`z
gives you the advantage of preserving the cursor position.
You can also try <C-x><C-l> which will repeat the last line from insert mode and brings you a completion window with all of the lines. It works almost like <C-p>
For someone who doesn't know vi, some answers from above might mislead him with phrases like "paste ... after/before current line".
It's actually "paste ... after/before cursor".
yy or Y to copy the line
or
dd to delete the line
then
p to paste the copied or deleted text after the cursor
or
P to paste the copied or deleted text before the cursor
For more key bindings, you can visit this site: vi Complete Key Binding List
I know I'm late to the party, but whatever; I have this in my .vimrc:
nnoremap <C-d> :copy .<CR>
vnoremap <C-d> :copy '><CR>
the :copy command just copies the selected line or the range (always whole lines) to below the line number given as its argument.
In normal mode what this does is copy . copy this line to just below this line.
And in visual mode it turns into '<,'> copy '> copy from start of selection to end of selection to the line below end of selection.
Default is yyp, but I've been using this rebinding for a year or so and love it:
" set Y to duplicate lines, works in visual mode as well.
nnoremap Y yyp
vnoremap Y y`>pgv
I prefer to define a custom keymap Ctrl+D in .vimrc to duplicate the current line both in normal mode and insert mode:
" duplicate line in normal mode:
nnoremap <C-D> Yp
" duplicate line in insert mode:
inoremap <C-D> <Esc> Ypi
1 gotcha: when you use "p" to put the line, it puts it after the line your cursor is on, so if you want to add the line after the line you're yanking, don't move the cursor down a line before putting the new line.
For those starting to learn vi, here is a good introduction to vi by listing side by side vi commands to typical Windows GUI Editor cursor movement and shortcut keys. It lists all the basic commands including yy (copy line) and p (paste after) or P(paste before).
vi (Vim) for Windows Users
If you would like to duplicate a line and paste it right away below the current like, just like in Sublime Ctrl+Shift+D, then you can add this to your .vimrc file.
nmap <S-C-d> <Esc>Yp
Or, for Insert mode:
imap <S-C-d> <Esc>Ypa
I like to use this mapping:
:nnoremap yp Yp
because it makes it consistent to use alongside the native YP command.
I use this mapping, which is similar to vscode. I hope it is useful!!!.
nnoremap <A-d> :t. <CR>==
inoremap <A-d> <Esc>:t. <CR>==gi
vnoremap <A-d> :t$ <CR>gv=gv

Resources