Completely de-indent visual block [duplicate] - vim

This question already has answers here:
Remove all arbitary spaces before a line in Vim
(9 answers)
Closed 8 years ago.
How can I map a key to completely de-indent a visual block?
The best method I know for doing this "manually" is de-indenting once with < and then repeatedly pressing ., so the mapping is:
vmap <leader>d <.................
This does work but I'd like to know the "right" way to do this. The above also only works for however many .s there are.

use the steps in this page to completely trim white spaces from the left for a range
Step by step:
Select your block ( shift-v)
:left or :le
<CR>
That should do it

You can add a count to <; I usually do 50<, which will de-indent it 50 times, which should almost always be enough.
From :help <:
{Visual}[count]< Shift the highlighted lines [count] 'shiftwidth'
leftwards (for {Visual} see Visual-mode). {not in
Vi}

Instead of using the < key to de-indent you can simply delete all the whitespace in each line before the first character. You can do so by adding:
let #y = '0d^j'
In order to run this on every line of the selected block, enter command mode by typing : and complete the command to:
:'<,'>normal #y
Then again you can record another macro to do so:
let #q = ':normal #y'
Using this approach, you will eventually be able to de-indent a visual block by typing #q, which calls the macro #y in the background.
Explanation of the first macro:
0 will move the cursor to the beginning of the line,
d^ will delete all whitespace until the first character and
j will move the cursor to the line below

Related

Can vim markers work with the repeat key?

I regularly use the . key to repeat my last vim command. I'm wondering if there's a way to use it with commands performed using markers. Here's a simple example:
Mark a line of text using m'a
Move down a few lines, e.g. 5j
Indent the lines using >'a -- indents 6 lines
Press . to repeat above command on the same 6 lines -- will only affect 1st line
Is there a way to get vim to apply the same marker range of the previous command when using the . command?
ps. I know the above example would have been easier with 6>>, which works with the ., I'm just using it as an example. I often use markers for more complex/longer commands.
The problem is that the command you're repeating is >'a, but because of the rule "After applying the operator the cursor is mostly left at the start of the text that was operated upon" (from :help operator), >'a leaves the cursor at mark a if that was above your starting position. Then when you repeat >'a you end up with a linewise motion from that line to itself, which only re-indents one line.
Since you're left at the beginning of the block of text, to affect the same block of text again you can use the '] (linewise) or `] (charwise) motions, which move to the end of the block of text just affected. So you can use >'] to indent the same block again, and since your cursor starts and ends at the same position this time, you can repeat it additional times with ..
A simpler choice, though, would be to just use V5j> instead of ma5j>'a. V starts visual mode (linewise) at your current position, 5j moves down 5 lines, and then > indents. And when you repeat using ., the same visual selection still pertains, so you get the desired result whether you moved up or down.

What is the best way to refactor a Ruby ‘if’ statement into one-line shorthand form in Vim?

I have the following Ruby code:
if some_cond && another
foo_bar
end
and I want to change it to:
foo_bar if some_cond && another
What are the most idiomatic ways to do that in Vim?
Assuming that the cursor is located at the if-line prior to
refactoring (not necessarily at the beginning of that line),
I would use the following sequence of Normal-mode commands:
ddjVpkJ<<
or this chain of Ex commands:
:m+|-j|<|+d
Here the if-line is first moved down one line by the :move + command.
The :move command cuts a given range of lines (the current line, if
not specified) and pastes it below the line addressed by the argument.
The + address is a shorthand for .+1 referring to the next line
(see :help {address}).
Second, the line containing the body of the conditional statement is
joined with the just moved if-line. The :join command concatenates
a given range of lines into a single line. The - range is a shortened
form of the .-1 address referring to the line just above the cursor
(see :help {address}).
Third, the newly joined line is unindented by one shiftwidth using
the :< command.
Finally, the remaining end-line, which can now be addressed as +,
is removed by the :delete command.
I see few (probably non-optimal) solutions:
cursor in first character in first line:
D - remove if condition but leave cursor in same position (don't delete line)
J - join next line to current
A <Space> <ESC> - append space and exit to Normal mode
p - paste if condition
and then remove remaining end with jdd
cursor in first character in first line, as previously:
j - move to next line
dd - remove this line
k - move back to if condition
P - paste removed line before actual line, cursor should be placed to pasted line
J - join next line to current
== or << - unindent current line
and then remove remaining end with jdd
another solution:
j - move to second line
JD - join line with next, remove what was joined
dd - remove current line
k - step to previous line
PJ<< - paste, join and unshift
It's probably not optimal, but I do it without thinking, because most of this commands are in my muscle memory (you don't think how to move around you, how to yank/delete and paste most of the time, and joining line is also helpful to remember).
If you have virtualedit enabled in config, instead of A <Space> <Esc> you can $ <Space>, but I find $ harder to use than A followed by Ctrl-[ (it's simmilar to ESC).
As an advice: if you use some upper letter commands, try to chain them if it's possible, so you only need to keep Shift pressed and then execute some commands, instead of mixing upper and lower letter commands and pressing two keys at a time (upper letter is 2 key press, one is Shift). Once I found combo helpful for restarting server in console Ctrl+cpj, which sends Ctrl+c, Ctrl+p (previous command) and Ctrl+j (Enter key) with single Ctrl press. Since then I try to find simmilar time-saving combination in Vim too mostly with Shift, as Ctrl is not much used in Vim.
Yet another way:
ddpkJjdd
ddp swap the two lines
kJ move up and join the lines
== re-indent the line
jdd move down and delete the last line
There are probably 30 ways to do this.
Here is one, assuming you are starting from the end of the word end in normal mode:
dd (delete last line)
"aD (delete and copy foo_bar to buffer a)
dd (delete now-empty line 2)
"aP (paste from buffer a before caret)
aSpaceEsc (insert space and return to normal mode)
Again, "properly" rarely applies in Vim because there are so many ways to accomplish something. This is so small a change that even re-typing foo_bar could be justifiable.

Indent or comment several text lines with vi

can vim or vim be used to comment or indent at the same time a number of lines? For instance:
for item in Lista:
ind = int(floor(1.0*(item-lmin)/width))
if ind==nintervals:
ind=ind-1
print item,ind
comment it to:
#for item in Lista:
#ind = int(floor(1.0*(item-lmin)/width))
#if ind==nintervals:
#ind=ind-1
#print item,ind
or indent it to:
for item in Lista:
ind = int(floor(1.0*(item-lmin)/width))
if ind==nintervals:
ind=ind-1
print item,ind
P.D. Is relevant the difference between VI and VIM?
here is another way.
block lines with ctrl+v
Insert comment sign (//) with I
escape with ESC
the key typing is
ctrl+v → jjjj → I → // → ESC
To comment, press a capital V to enter VISUAL LINE mode, select all lines, then press : to enter command mode and use the command (note that VIM already include the '<,'>marks for you):
:'<,'>s/^/#/
If you prefer hash marks near the text, and not near the left margin, the command is:
:'<,'>s/^\(\s*\)/\1#/
To indent, select the block the same, then type > to indent, < to unindent.
type :set number. take note of the start and end line number of the block you want to comment. then do an address range substitution, eg
:12,17s/^/#
Lots of answers here, all with a theme. The best way to do it really depends on context (because context determines the easiest navigation method), so I'll make some assumptions about the context. If the section you want to indent or comment is a single paragraph (eg, you want to indent or comment everything from the cursor up to the next blank line), you can indent with:
>)
If the cursor is not on the start of the paragraph, but the section you want to indent is a single paragraph and the cursor is in the middle, use
>ip
Finally, suppose you want to indent a block of code delimited by {}, and the cursor is in the middle of that block. Use
>i{
To comment, in each case just replace the > with v and use the above commands to make a block selection, then do a text replace like s/^/#/.
The key is the navigation commands. I highly recommend
:help v_a
Similar to the accepted answer, but easier for blocks or paragraphs:
Block lines: Ctrl + V
Select paragraph: }
Insert mode: I (uppercase i)
Type character to insert: # (with space after char, no Enter!)
Press: ESC
This should auto complete the character in all the selected block.
Basically the diference with the accepted answer is that instead of using j to go down line by line you use } to select the whole paragraph (or you could use G for end of file, for ex.
Short version:
Ctrl + V + } + I + # + ESC
I know there are a zillion answers here already explaining how to use > and < for indentation, so I'm not going to bother with that. With respect to the commenting, though, while you can do it quick and dirty with a block insert or a substitution, you can do way better with the NERD Commenter plugin. It provides commands to comment and uncomment in various ways, it knows what comment symbol to insert based on the syntax, and it can do pretty multi-line comments if the language supports them.
Select the lines using visual mode.
To indent once type >> or << to indent right or left respectively. To indent n times type n>> or n<<.
To comment out do replace the beginning of the line with the comment:
:'<,'>s/^/#/
'<,'> means "from the beginning of the selection until the end.
s/^/#/ replaces the beginning of each line in the range with #, assuming # makes a line into a comment.
Put your cursor on the first line, count how many lines should be indented, in the above example it's 5, then for hash (#) type
:.,.+5%s/^\([ <tab>]*\)/#\1/<enter> or for a tab indentation,
:.,.+5%s/^\([ <tab>]*\)/<tab>\1/<enter>,
<tab> and <enter> are the tab and enter keys.
There are probably more elegant ways of doing this, but something like this is a quick-n-dirty thing.
For commenting you could use VISUAL BLOCK selection (Ctrl-V) and select the beginnings of the lines, then press Shift-I and write one #. After pressing Esc all the lines get the #.
My usual solution is:
<ESC>
<q><a> => start a macro and save it as macro a
<^> => to get to the start of the line
<i> => insert mode
<#> => Add the #
<ESC> => End insert mode
<down> => Move to the next line
<q> => End macro
Then once:
<[at]><a> => repeat macro a
Then just repeat <[at]><[at]> (repeat last executed macro) until all lines are commented. You can just hold <[at]> and let keyboard repeat do the rest.
BTW: How do you write an [at] sign here without stackoverflow turning it into "> blockquote"?
To indent:
[shift] + [v] => line select mode
[down] => until all lines to indent are selected
then:
[>] => indent once
or:
[2..x][>] => indent 2..x levels
If you are using Python (or other languages that use # as comment), a faster way to comment multiple lines would be:
Enter visual block mode (Ctrl+v) from the start of the line.
Go down as needed (j multiple times).
Replace space with # by pressing r then #.
To uncomment, do the same but for step three replace it with space.

Vim: Split Words Into Lines?

I frequently use Shift+J in visual mode to join several selected lines into a single line with the original lines separated by spaces. But I am wondering if there is an opposite shortcut such that it will split selected words into separate lines (one word per line).
Of course I can do:
:'<,'>s/ /^M/g
But something more succinct in terms of keystrokes would be very useful. Has anyone else found a way to do this?
Thanks in advance,
-aj
Map it if you are using it often in your ~/.vimrc file or similar
vnoremap \ll :'<,'>s/ /^M/g<cr>
nnoremap \ll :s/ /^M/g<cr>
if you are only wanting to to it multiple times now you can use & command to repeat last search also
Theres also gqq but thats for textwidth eg 80 chars
Recently I stumbled across the same problem. My solution is the following vim function (put in my .vimrc):
function SplitToLines() range
for lnum in range(a:lastline, a:firstline, -1)
let words = split(getline(lnum))
execute lnum . "delete"
call append(lnum-1, words)
endfor
endfunction
This can be used with line ranges, e.g., as follows
:26call SplitToLines()
which would split line number 26. But the code also handles ranges of lines gracefully (that's why the range in the for loop is built in reverse order).
1,10call SplitToLines()
will split lines 1 to 10 into several lines. However, I mostly use this in visual mode, like
'<,'>call SplitToLines()
which splits all lines that are visually marked. Of course you may define some single letter abbreviation for this function call (with auto completion by Tab I do not find it necessary). Also note that by adding an additional argument which would also be used by 'split' you can have a function that does split lines at specific patterns (instead of just white space).
I use this in my config to Un-Join/split the last word on current line:
nnoremap <C-J> g_F<Space><Space>i<CR><Esc>k
It maps CTRL-j to do the opposite of Join, I think of it as Counter-Join :) I mostly use it to convert between K&R style vs ...the other kind of curly brace placement.
g_ : search for the last non-whitespace on current line
F<Space> : reverse-find first space
<Space> : go one character forward
i : enter insert mode
<CR> : insert a line break
<Esc> : return to normal mode
k : go up one line to where we begun

In Vim, what is the best way to select, delete, or comment out large portions of multi-screen text?

Selecting a large amount of text that extends over many screens in an IDE like Eclipse is fairly easy since you can use the mouse, but what is the best way to e.g. select and delete multiscreen blocks of text or write e.g. three large methods out to another file and then delete them for testing purposes in Vim when using it via putty/ssh where you cannot use the mouse?
I can easily yank-to-the-end-of-line or yank-to-the-end-of-code-block but if the text extends over many screens, or has lots of blank lines in it, I feel like my hands are tied in Vim. Any solutions?
And a related question: is there a way to somehow select 40 lines, and then comment them all out (with "#" or "//"), as is common in most IDEs?
Well, first of all, you can set vim to work with the mouse, which would allow you to select text just like you would in Eclipse.
You can also use the Visual selection - v, by default. Once selected, you can yank, cut, etc.
As far as commenting out the block, I usually select it with VISUAL, then do
:'<,'>s/^/# /
Replacing the beginning of each line with a #. (The '< and '> markers are the beginning and and of the visual selection.
Use markers.
Go to the top of the text block you want to delete and enter
ma
anywhere on that line. No need for the colon.
Then go to the end of the block and enter the following:
:'a,.d
Entering ma has set marker a for the character under the cursor.
The command you have entered after moving to the bottom of the text block says "from the line containing the character described by marker a ('a) to the current line (.) delete."
This sort of thing can be used for other things as well.
:'a,.ya b - yank from 'a to current line and put in buffer 'b'
:'a,.ya B - yank from 'a to current line and append to buffer 'b'
:'a,.s/^/#/ - from 'a to current line, substitute '#' for line begin
(i.e. comment out in Perl)
:'s,.s#^#//# - from 'a to current line, substitute '//' for line begin
(i.e. comment out in C++)
N.B. 'a (apostrophe-a) refers to the line containing the character marked by a. ``a(backtick-a) refers to the character marked bya`.
To insert comments select the beginning characters of the lines using CTRL-v (blockwise-visual, not 'v' character wise-visual or 'V' linewise-visual). Then go to insert-mode using 'I', enter your comment-character(s) on the first line (for example '#') and finally escape to normal mode using 'Esc'. Voila!
To remove the comments use blockwise-visual to select the comments and just delete them using 'x'.
Use the visual block command v (or V for whole lines and C-V for rectangular blocks). While in visual block mode, you can use any motion commands including search; I use } frequently to skip to the next blank line. Once the block is marked, you can :w it to a file, delete, yank, or whatever. If you execute a command and the visual block goes away, re-select the same block with gv. See :help visual-change for more.
I think there are language-specific scripts that come with vim that do things like comment out blocks of code in a way that fits your language of choice.
Press V (uppercase V) and then press 40j to select 40 lines and then press d to delete them. Or as #zigdon replied, you can comment them out.
The visual mode is the solution for your main problem. As to commenting out sections of code, there are many plugins for that on vim.org, I am using tComment.vim at the moment.
There is also a neat way to comment out a block without a plugin. Lets say you work in python and # is the comment character. Make a visual block selection of the column you want the hash sign to be in, and type I#ESCAPE. To enter a visual block mode press C-q on windows or C-v on linux.
My block comment technique:
Ctrl+V to start blockwise visual mode.
Make your selection.
With the selection still active, Shift+I. This put you into column insert mode.
Type you comment characters '#' or '//' or whatever.
ESC.
Or you may want to give this script a try...
http://www.vim.org/scripts/script.php?script_id=23
For commenting out lines, I would suggest one of these plugins:
EnhancedCommentify
NERD Commenter
I find myself using NERD more these days, but I've used EnhancedCommentify for years.
If you want to perform an action on a range of lines, and you know the line numbers, you can put the range on the command line. For instance, to delete lines 20 through 200 you can do:
:20,200d
To move lines 20 through 200 to where line 300 is you can use:
:20,200m300
And so on.
Use Shift+V to go in visual mode, then you can select lines and delete / change them.
My usual method for commenting out 40 lines would be to put the cursor on the first line and enter the command:
:.,+40s/^/# /
(For here thru 40 lines forward, substitute start-of-line with hash, space)
Seems a bit longer than some other methods suggested, but I like to do things with the keyboard instead of the mouse.
First answer is currently not quite right?
To comment out selection press ':' and type command
:'<,'>s/^/# /g
('<, '> - will be there automatically)
You should be aware of the normal mode command [count]CTRL-D.
It optionally changes the 'scroll' option from 10 to [count], and then scrolls down that many lines. Pressing CTRL-D again will scroll down that same lines again.
So try entering
V "visual line selection mode
30 "optionally set scroll value to 30
CTRL-D "jump down a screen, repeated as necessary
y " yank your selection
CTRL-U works the same way but scrolls up.
v enters visual block mode, where you can select as if with shift in most common editors, later you can do anything you can normally do with normal commands (substitution :'<,'>s/^/#/ to prepend with a comment, for instance) where '<,'> means the selected visual block instead of all the text.
marks would be the simplest mb where u want to begin and me where u want to end once this is done you can do pretty much anything you want
:'b,'ed
deletes from marker b to marker e
commenting out 40 lines you can do in the visual mode
V40j:s/^/#/
will comment out 40 lines from where u start the sequence

Resources