how to shift (indent) yanked lines in vi - vim

I already know many ways to shift (indent - and autoindent) lines in vi, but I was wondering if it is possible to mark/yank a block of lines and indent them.
I already tried the obvious (esc ma y'a >>) but that didn't work.

This is a confusing question if there is one. Your "obvious" attempt seems more "random" than "obvious":
you go back to normal mode with <Esc>,
you place mark a with ma,
you yank the text from the cursor to mark a with y'a, which doesn't do anything useful because the cursor is already on mark a,
and then you indent the current line with >>.
Which begs a few questions:
Why do you yank at all?
Yanking and indenting are completely orthogonal so that y has nothing to do here.
Why do you not move the cursor?
If you don't move the cursor, then there is no point placing a mark.
Why do you use >>?
[count]>> doesn't know anything about marks: it indents [count] lines.
What I think you are trying to do is something like this:
ma " place mark a
jjj " move the cursor to another line
>'a " indent from current line to mark a
Where…
ma is the same ma as in your "obvious" attempt,
jjj is just an example motion,
>'a is the operator > (not to be confused with >>), followed by the motion 'a.
But you probably don't need marks to begin with:
>/foo<CR> " indent from current line to next line matching foo

Related

How can I select all the text on a line without the indentation in Vim?

I want to replace all the text of the current line under the cursor and change the text so I start typing the new code. But I want to keep the indentation.
Currently I am using ddO. This will delete the line and open a line before the cursor in insert mode, it's good because vim will take notice of the previous indentation and place the cursor as expected.
But I want to use c similar to ciw (change inner word) because it feels natural to think "change the line". Vc is almost what I want but it will lose the indentation.
Any idea ?
Maybe you are looking for cc?
:h cc
["x]cc Delete [count] lines [into register x] and start
insert |linewise|. If 'autoindent' is on, preserve
the indent of the first line.
You can try this (to put in your vimrc):
:onoremap ii :<c-u>normal! v^o$h<cr>
:xnoremap ii ^o$h
The first line defines the mapping ii which will work with any command expecting a motion (cii, dii, yii...).
The second mapping allows to use it in visual mode (e.g., vii).
Brief explanation of the :normal! command:
v : visual mode, ^ : go to 1st non-blank char, o : go to the opposite side of the selection, $h : go past to the end of line then go 1 char left.

Vim - move rest of line to new line above

How does one get from
int lel = 123; // this is a comment
^
to
// this is a comment
int lel = 123;
preferably when starting in insert mode, and with the right indentation?
My current way of doing it is C-c l d$ O C-c p, but as my auto-indent isn't perfect, the inserted line in not indented at all.
I think some editors use space+enter or something for this (at least I think I've seen it).
Is this possible in vim by default?
Still not a very pretty answer, but assuming the cursor is where the "^" is above, another option would be:
d0=:puEnter
d0 deletes til the beginning of the line.
= reindents over the next motion.
:pu short for :put
Enter to run the command.
I would probably use
DO<c-r>"
D deletes to the end of line. O opens the line above in insert mode (with the correct indentation). <c-r>" pastes the part that was deleted with D.
(This ends in insert mode)
New answer:
d^o<c-u><esc>p
Figured it out. This was one of my early attempts, but in the form <esc>d^o<esc>p, which has the problem that the inserted line gets a comment leader. <c-u> fixes that.
d^o<c-u><c-o>p
is of course useful if one wants to stay in Insert mode.
Earlier answer:
This solution works, but the answer by Randy Morris is better.
Suggested key sequence:
<esc>mpa<cr><esc>dd`pP`pa
(Where p can be replaced with any other mark.)
This means <esc> enter Normal mode, mp mark current position as p, a enter Insert mode, <cr> break the line and put the comment on the next line at the correct indentation, <esc> go to Normal mode, dd delete line, `p go to the marked position, P put the deleted line before the current line, `p go to the marked position, a go to Insert mode. To avoid wearing your fingers out, map it:
:inoremap <F2> <esc>mpa<cr><esc>dd`pP`pa
The indentation will not be correct if the comment is at the end of a line that increases or decreases indentation.
Simpler sequence that will not work on the last line in the buffer
To perform this operation on a line that isn't the last line in the buffer, the following will do. With the cursor on the first slash, in Insert mode: <cr><esc>ddkPjA.
The <cr> breaks the line and puts the comment at the correct indentation, <esc> go to Normal mode, dd delete line, k go to previous line, P put the deleted line before the current line, jA to end up in Insert mode where you were when you started.
To map it:
:inoremap <F2> <cr><esc>ddkPjA

Delete backwards from cursor to the end of the previous line in Vim?

Say I want to edit the following line:
var myVar =
"I am a string!";
So that it looks like this:
var myVar = "I am a string!";
Is there a movement that goes to the end of the previous line?
What you want is the line join command, J.
In normal mode, put your cursor anywhere on the var myVar = line and type J (capital j).
Direction-wise motions work with J - 5J indents 5 lines below the cursor, etc. You can also select a range of lines using visual mode (v to start visual mode selection) and join them all into one using J.
The &joinspaces option affects this behavior as well. When it's "on" (set joinspaces or set js) it adds two spaces after a sentence-ending mark (i.e. '.', '?', or '!') when joining lines. set nojoinspaces or set nojs to turn that off and insert only one space.
Also,
:set backspace=indent,eol,start
The backspace option determines the behavior of pressing the backspace key (). By default, Vim’s backspace option is set to an empty list. There are three values that can be added that each independently alter the behavior of the backspace key. These are indent, eol, and start.
When indent is included, you can backspace over indentation from autoindent. Without it, Vim will not allow you to backspace over indentation.
When eol is included, you can backspace over an end of line (eol) character. If the cursor is at the first position of a line and you hit backspace, it will essentially be joined with the line above it. Without eol, this won’t happen.
When start is included, you can backspace past the position where you started Insert mode. Without start, you can enter Insert mode, type a bit, and then when backspacing, only delete back as far as the start of Insert mode.
The backspace default is absurd, you are going to want to add all of the above to your Vim settings.
See :h 'backspace' for more details.
kJ will do what you want and is probably what you should be using, however if you want to do exactly what you've asked for Delete backwards from cursor to the end of the previous line then you can do the following:
:set virtualedit+=onemore
^ " go to the start of the line
d?$<cr>
?$<cr> is a movement that goes to the end of the previous line.
:set virtualedit+=onemore allows the cursor to move just past the end of the line, without which we would end up deleting the last character of the line, which in the example you have given would be the trailing space.
You could then create a mapping to do this (:nohl just clears the search highlighting):
:nnoremap <leader>J ^d?$<cr>:nohl<cr>
Although a simpler mapping to achieve the same thing would be:
:nnoremap <leader>J kJ

Vim: Indent with one space (not shiftwidth spaces)

The default VIM indentation commands indent by shiftwidth spaces
e.g.
>> Indent line by shiftwidth spaces
<< De-indent line by shiftwidth spaces
Is there any way to indent with one or n (where n != shiftwidth) space(s)?
One way to do that is to vertically select a column in the block with Ctrl+V then, I to insert vertically and then type a space and <Esc>. But is there a better way?
I'm not sure that there is a better way. But, there are a few ways that you could do it (that I can think of anyway)...
Your Visual Block Solution
Like you said: press Ctl-V select the lines you want, press I to insert, and enter the number of spaces.
Search
Similar to the above but a little more flexible - you can use with with the 'select paragraph' vip command, or any range really: press v or vip or what have you to select the range, and the type :s/^/{n spaces} where {n spaces} is the number of spaces you want to insert.
Its a little more verbose, but works pretty well for pretty much any range. Heck, if you wanted to do the whole file you could do Ctl-A (OS dependent) and indent the whole file (or just skip the whole visual mode thing and just do it command mode...as in :1,$s/^/{n spaces}
Note that you don't have to include the third slash in s/// since you aren't putting any switches at the end of the search.
Global
Maybe you want to only indent lines that match some pattern. Say...all lines that contain foo. No problem: type :g/foo/s/^/{n spaces}
Global is especially handy if its multi-line sections with a similar pattern. You can just escape into normal mode land and select the lines you want and indent accordingly: :g/foo/norm Vjj:s/^/{n spaces}Ctl-V{Enter}. Little more complicated with that extra Ctl-V{Enter} at the end but useful under certain circumstances.
Use tabstop and shiftwidth
Yes, if your doing it a lot - I'd do :set ts=2 and :set et and :set sw=2 and use >> and << every which way...
Make a Function
Okay, so still not brief enough and for whatever reason you need to do this a lot and you can't abide messing with sw, et and ts settings. No problem, just write up a quick function and give it a localleader mapping:
function! AddSpace(num) range
let s:counter = 0
let s:spaces = ''
while s:counter < a:num
let s:spaces .= ' '
let s:counter = s:counter + 1
endwhile
execute a:firstline .','. a:lastline .'s/^/'. s:spaces
endfunction
:map <LocalLeader>i :call AddSpace(3)Ctl-V{enter}
Maybe just knowing more than one way to do this is better than only knowing one? After all, sometimes the best solution depends on the problem :)
Indent a block of code in vi by 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 3 spaces, type le 3 and press enter. This is what appears: :'<,'>le 3
The selected text is immediately indented to 3 spaces.
Indent a block of code in vi by three spaces with Visual Line mode:
Open your file in VI.
Put your cursor over some code
Be in normal mode press the following keys:
Vjjjj:le 3
Interpretation of what you did:
V means start selecting text.
jjjj arrows down 4 lines, highlighting 4 lines.
: tells vi you will enter an instruction for the highlighted text.
le 3 means indent highlighted text 3 lines.
To change the number of space characters inserted for indentation, use the shiftwidth option:
:set shiftwidth = <number>
Have a look here for more details.
You can also add that to your .vimrc file.
If I'm understanding correctly, you could use:
ctrl+V, jj then ':le n', where n is the number of spaces to indent.
http://vim.wikia.com/wiki/Shifting_blocks_visually
Place marks ('a' and 'b') between the code you want to indent:
<position cursor at top of block>
m a
<position cursor at bottom of block>
m b
Do a replace command such that each newline character between your marks is replaced with the number of spaces desired (in this example, 2 spaces):
:'a,'bs/^/ /g
If white space indentation already exists and you want to increase it further by one or more columns, then select a block of one or more white space columns using Ctrl-V, yank and paste it in the same place.
I had to dedent by a given number of spaces, amount, inside a vim script. This worked:
let sw_setting = &shiftwidth
set shiftwidth=1
exe "normal v" . amount . "<"
let &shiftwidth = sw_setting
A side-effect is that it resets the last visual mode selection. Instead, you may wish to edit the exe... line such that it executes "<<" repeated amount times in normal mode. That is: instead of normal v3<, make it normal <<<<<<, if amount is 3.
I like to use Space to indent a visual selection with a single space:
vnoremap <silent> <space> :s/^/ /<CR>:noh<CR>gv
And I couldn’t get Shift+Space to dedent, so I use z:
vnoremap <silent> z :s/^\s\=//<CR>:noh<CR>gv

How do I insert a linebreak where the cursor is without entering into insert mode in Vim?

Is possible to insert a line break where the cursor is in Vim without entering into insert mode? Here's an example ([x] means cursor is on x):
if (some_condition) {[ ]return; }
Occasionally, I might want to enter some more code. So I'd press i to get into insert mode, press Enter to insert the line break and then delete the extra space. Next, I'd enter normal mode and position the cursor before the closing brace and then do the same thing to get it on its own line.
I've been doing this a while, but there's surely a better way to do it?
For the example you've given, you could use rEnter to replace a single character (the space) with Enter. Then, fspace. to move forward to the next space and repeat the last command.
Depending on your autoindent settings, the above may or may not indent the return statement properly. If not, then use sEnterTabEsc instead to replace the space with a newline, indent the line, and exit insert mode. You would have to replace the second space with a different command so you couldn't use '.' in this case.
A simple mapping to break the line at the cursor by pressing Ctrl+Enter:
:nmap <c-cr> i<cr><Esc>
essentially enters 'insert' mode, inserts a line break and goes back to normal mode.
put it in your .vimrc file for future use.
Here's how to create a macro that inserts a newline at the cursor whenever you press 'g' while not in insert mode:
From within vim, type:
:map g i[Ctrl+V][Enter][Ctrl+V][Esc][Enter]
Where:
[Ctrl+V] means hold the Ctrl key and press 'v'
[Enter] means press the Enter key
[Esc] means press the Esc key
You'll see the following at the bottom of your vim window until you press the final Enter:
:map g i^M^[
Explanation:
[Ctrl+V] means "quote the following character" -- it allows you to embed the newline and escape characters in the command.
So you're mapping the 'g' key to the sequence: i [Enter] [Escape]
This is vim for insert a newline before the cursor, then exit insert mode.
Tweaks:
You can replace the 'g' with any character that's not already linked to a command you use.
Add more to the command, e.g. f}i^M^[O -- This will find the } and insert another newline, then escape from insert mode and Open an empty line for you to enter more code.
You can add the command to your .vimrc or .exrc file to make it permanent. Just omit the colon from the beginning, so the command starts with "map"
Enjoy!
If you're usually expanding a one line block to three lines, try substitution. Change the opening bracket into bracket/return, and the closing bracket into return/bracket.
The command for substituting bracket/return for bracket looks like this:
:s/{/{\r/
Since you want to use this often, you could map the full sequence to an unused keystroke like this:
:map <F7> :s/{/{\r/ ^M :s/}/\r}/ ^M
Where you see ^M in the sequence, type [Ctrl-V], then press enter.
Now with your cursor anywhere on your sample line, press the mapped key, and the carriage returns are added.
Check :help map-which-keys for advice on selecting unused keystrokes to map.
Assuming you're okay with mapping K to something else (choose a different key of your liking), and using marker ' as a temporary marker is okay why not do this?
:nmap K m'a<CR><Esc>`'
now pressing K in normal mode over the character after which you want the line break to occur will split the line and leave the cursor where it was.
Basically, when you split a line you either want to just insert a carriage return, or in the case that you're on a space, replace that with a carriage return. Well, why settle for one or the other? Here's my mapping for K:
"Have K split lines the way J joins lines
nnoremap <expr>K getline('.')[col('.')-1]==' ' ? "r<CR>" : "i<CR><Esc>"
I use the ternary operator to condense the two actions into one key map. Breaking it down, <expr> means the key map's output can dynamic and in this case hinges on the condition getline('.')[col('.')-1]==' ' which is the long winded way to ask vim if the character under the cursor is a space. Finally, the familiar ternary operator ? : either replaces the space with linebreak (r<CR>) or inserts a new one (i<CR><Esc>)
Now you have a lovely sister key map to the J command.
Vim will automatically kill any whitespace to the right of the cursor if you break a line in two while autoindent (or any other indentation aid) is enabled.
If you do not want to use any of those settings, use s instead of i in order to substitute your new text for the blank rather than just inserting. (If there are multiple blanks, put the cursor on the leftmost and use cw instead.)
In fact you need the following combined operations:
Press v to enter Visual Mode
Select the line you want to split
Press : to enter in Command Mode
s/\s/\r/g
Done
If you have the input:
aaa bbb ccc ddd
and want to output
aaa
bbb
ccc
ddd
You can use the command
f r<ENTER>;.;.
o ESC command will do it for you.
Set this key mapping in your vimrc
:map <C-m> i<CR><Esc>h
Then press Ctrl+m if you want to use it in your vim.
IMHO, the built-in mapping gs is not a useful mapping (put vim to sleep), one could use this for splitting:
nmap gs i<CR><ESC>
In Vrapper you can use gql which will split a line without entering insert mode, but may not always maintain indentation.
I found this to be the most faithful implementation of what I'd expect the opposite behaviour to J
nnoremap S i<cr><esc>^mwgk:silent! s/\v +$//<cr>:noh<cr>`w
It does the simplistic new line at cursor, takes care of any trailing whitespace on the previous line if there are any present and then returns the cursor to the correct position.
i <cr> <esc> - this is one of the most common solutions suggested, it doesn't delete non-whitespace characters under your cursor but it also leaves you with trailing whitespace
^mw - goto start of new line and create a mark under w
gk - go up one line
:silent! s/\v +$//<cr> - regex replace any whitespace at the end of the line
:noh<cr> - Clear any search highlighting that the regex might have turned on
`w - return the the mark under w
Essentially combines the best of both r<esc><cr> and i<cr><esc>
Note: I have this bound to S which potentially overwrites a useful key but it is a synonym for cc and since I don't use it as often as I do splits I am okay with overwriting it.
This mapping will break up any one-line function you have. Simply put your cursor on the line and hit 'g' in normal mode:
:map g ^f{malr<CR>`a%hr<CR>`a
This assumes that you have a space after the opening brace and a space before the closing brace. See if that works for you.

Resources