Vim copy line and comment out old line - vim

I'm trying to achieve the same thing asked here, but in Vim.
Duplicate line and comment out old one
Basically I want to yank line, comment out the old one, paste new one, and keep cursor at the beginning of new line and end in insert mode.
For example:
def func (param)
will change to:
//def func (param)
def func (param)
I recorded a macro for it, put it into .vimrc and I'm using it via #y
" copy-and-comment-line macro
" yank line, comment out original line, move cursor at the begining
" of copied line and end in insert mode
let #y='yypkui//kdklkl'
(I'm not sure it will work for you as it contains unprintable ~# characters which code block won't display)
Macro works, but is there a built-in command in vim that I can achieve same thing with?

This mapping should do it for you:
nnoremap YOURKEY YI//<esc>p
The cursor will be on the pasted line.
replace YOURKEY by a key (or keys) you like
Note that this answer works only for your example, //style comment. If you want it to be generic solution, you have to build a function, in this function check the filetype, and decide which comment style should be used. There is no good built-in solution so far, but you can check the NERDCommenter or vim-commentary plugins to see how they achieve this, or you can install one of them (or a similar plugin) and call it's function in your mapping.

Related

vim, create new line after or before selected line

In vim I can jump to line number, for example, 14 like this : "14gg"; Then I can use "o" or "O" to create a new line after or before this line.
Is there a way to create a new line before or after 14th without jumping to it? Something like "14O" or "14o" (these commands don't work)
You can create a mapping in your .vimrc file for this, to map a single character to what you want to achieve. (Create a .vimrc in your home directory if you dont have one already i.e /home/user)
For example, put following lines in your .vimrc file
map e ggo
map E ggO
Now whenever you will do something like 14e, it will go to line 14 and insert a new line below and take you in insert mode. Likewise, E for inserting line above
Please note that this may override whatever functionality key e and E might have in vim.
I strongly recommend simply using 14ggo in a go to achieve what you want
Your question is a duplicate of this superuser question: https://superuser.com/questions/147715/vim-insert-empty-line-above-current-line-not-open-i-e-without-entering-inser
append() is the standard answer to your question:
:call append(14, '')
The cursor will not get moved, nor the position marks.
You can do:
14Go<Esc>
14GO<Esc>
or:
:14norm o
:14norm O
or:
:14put=
:14put!=
You'll need to jump back to where you come from anyway.

Storing vim macro - how to store a move-to-next-line operation?

I want to store a macro that inserts a symbol at the beginning of a line and then moves to the next line (such that I can call multiple of them)
I made a recording of what I want and then used ctrl R ctrl R to paste it directly into my vimrc where it came out as;
nmap #c I%<80>kd^[
The problem is when I then call it, "%<80>kd" gets inserted, instead of just the "%" symbol.
----More info:
As you can probably guess I'm trying to insert comments, I'd also like to remove them with a similar #x invocation. I want to be able to call this on whatever number of lines so it needs to finish with a move-to-next-line operation. I know about the alternative approach of using visual mode and I% esc esc, but I find this easier - I used to have it working but have lost my vimrc and now don't seem to be able to re-create it alas...
Add the following lines to your .vimrc.
To insert % in the begining of each line & move to next line:
let #c="I%\<esc>+"
To delete first character from the beginning of each line & move to next line
let #d="0x+"
nmap #c I%<ESC>j seems to work for me. I am able to paste that using "cp (paste from register c).
To delete the first character, nmap #d ^xj.

How do I re-select a range in vim? [duplicate]

Is it possible to reuse the range of ex commands in VIM?
As an example, I can write (copy) lines 4 to 10 from my current file to a new file using the following command:
:4,10w foo/bar.txt
But what I really want to do is move the lines to a new file. I can do this like so:
:4,10w foo/bar.txt
:4,10d
But it's a bit annoying to have to type 4,10 both times.
So I have two questions:
Generally, Is there a way to reference the previously used range in ex commands?
Specifically, if there is not a way to do (1), is there any easier way to cut and paste a number of lines from one file into a new one.
I usually use cat to do this:
:4,10!cat > foo/bar.txt
This works because you're piping the lines through cat and replacing them with the resulting output, which is nothing. And of course you can append to the end of an existing file by doing >> instead of >.
I am unaware of an answer to (1), but to answer (2), there are a number of different ways of doing it that don't require reselecting the lines by hand. In visual mode this will work:
4GV10G
:w foo/bar.txt
gvd
because gv reselects the previous selection, which is almost what you want, without using an ex range.
But you could just turn the problem on its head, and try:
:4,10d
:sp foo/bar.txt
pZZ
to cut, then paste into a new file, then close it.
Other than using the Vim history (:Cursor Up, q:) and removing the previous command so that just the range is kept, there's no way to re-use the last range, no magic variable.
If I used this move lines combination more often, I would write a custom command for it:
command! -bang -range -nargs=1 -complete=file MoveWrite <line1>,<line2>write<bang> <args> | <line1>,<line2>delete _
You need to specify the range only once and save typing.
You can write something like this for other combinations, too. The main challenge is specifying all the command attributes (bang, range, completion), and, later, remembering the custom command name.
Generally, what I do is delete the lines from the one file, switch to the other file, and paste.
Also, I generally use marks. Instead of typing the actual numbers, I hit mb to mark the beginning line, then go to the end line and hit d'b to delete back to the line marked as b. But you can use mb to mark a begin line, and me to mark an end line, then run an ex command:
:'b,'e w somefile.txt<Enter>
Of course you can use any letters from a through z for your marks; I usually use b and e but you can use what you like.
How I would move the lines:
m'b
<navigate to end line>
d'b
:n somefile.txt<Enter>
p
Ctrl+^
Ctrl+^ switches from the current open file to the previous open file. (You could also just open a pane and switch panes, if you prefer. Panes don't work in plain vi but do work in vim.)
The above assumes that you have set the autowrite option on. With autowrite, the :n command and Ctrl+^ both just write the current file and then switch files, instead of complaining that the file has been changed without you saving it. You can also do the above and just explicitly write the file before using :n or Ctrl+^.
By the way, I use Ctrl+^ so much that I mapped it onto K. Easier to type, but I got in that habit long ago when I used to have to sometimes use a dumb terminal that couldn't type Ctrl+^.
By the way, when you delete lines, they go into the "unnamed buffer". In vim, the unnamed buffer is preserved when you switch files. In original vi, the unnamed buffer is cleared. So the above won't work with old vi. You can make it work by deleting into a named buffer, then pasting from the named buffer; that works in any version of vi.
m'b
<navigate to end line>
"ad'b
:n somefile.txt<Enter>
"ap
Ctrl+^
The above deletes into the buffer named a, then pastes from a in the other file. This does work in vim of course; it's just that you don't need it.
Here's a command-line mapping that achieves this. I've bound it to CTRL-G CTRL-U, since it performs a similar action as CTRL-U. (But you can change that, of course!)
" c_CTRL-G_CTRL-U Remove all characters between the cursor position and
" the closest previous |:range| given to a command. When
" directly after a range, remove it.
" Useful to repeat a recalled command line with the same
" range, but a different command.
let s:singleRangeExpr = '\%(\d\+\|[.$%]\|''\S\|\\[/?&]\|/[^/]*/\|?[^?]*?\)\%([+-]\d*\)\?'
let s:rangeExpr = s:singleRangeExpr.'\%([,;]'.s:singleRangeExpr.'\)\?'
let s:upToRangeExpr = '^\%(.*\\\#<!|\)\?\s*' . s:rangeExpr . '\ze\s*\h'
" Note: I didn't take over the handling of command prefixes (:verbose, :silent,
" etc.) to avoid making this overly complex.
function! s:RemoveAllButRange()
let l:cmdlineBeforeCursor = strpart(getcmdline(), 0, getcmdpos() - 1)
let l:cmdlineAfterCursor = strpart(getcmdline(), getcmdpos() - 1)
let l:upToRange = matchstr(l:cmdlineBeforeCursor, s:upToRangeExpr)
if empty(l:upToRange)
return getcmdline()
else
call setcmdpos(strlen(l:upToRange) + 1)
return l:upToRange . l:cmdlineAfterCursor
endif
endfunction
cnoremap <C-g><C-u> <C-\>e(<SID>RemoveAllButRange())<CR>
as a plugin
My CmdlineSpecialEdits plugin has (among many others) this mapping as well.
You can also do something like this to write the contents of the anonymous register to file2.txt
:4,10d | :call writefile(split(##, "\n", 1), 'file2.txt')
You can do the deleting first, and then open a new tab and paste the contents - so :4,10d, then :tabe foo/bar.txt, followed by p... does that sound better?
In Vim 8 and NVIM 0.3.7 as of writing, you can actually edit your command list and hit enter to execute.
:4,10w foo/bar.txt
q:
q: is to enter interactive ex command
Once you open the interactive command list, you can then edit it and press enter to execute.
I love moopet's answer though, it's efficient.

Vim: insert text from a file at current cursor position

To insert text from a file in the current Vim buffer I use :r filename to insert the text below the cursor or :0r filename to insert in the first line.
How do you insert the contents of a file where [Cursor] is located?
Actual line with some coding [Cursor] // TODO for later version
Line below actual line ...
This inserts the contents of the file whose path is at the cursor position:
:r <cfile>
Insert a line break, read the file, and then take out the line break...
I propose Ctrl-R Ctrl-O = join(readfile('filename','b'), "\n")
Other solution:
Possibly open the other file in another window, use :%yh (h is a register name) and in your original file, in normal mode use "hp or "hP or in insert mode, Ctrl-R Ctrl-O h
To expand on the accepted answer with actual code, since I tried the suggestion and it worked nicely;
Here is an example of it working to insert a little php snippet:
`nnoremap <leader>php a<CR><ESC>:.-1read $SNIPPETS/php<CR>I<BS><ESC>j0i<BS><ESC>l`
In general the syntax is
`nnoremap [KEY SEQUENCE] a<CR><ESC>:.-1read [FILE PATH]<CR>I<BS><ESC>j0i<BS><ESC>l`
Just to break it down:
nnoremap : I'm about to define a new key mapping for normal mode
<leader>php : I would like to trigger the command sequence when this key combination is pressed. In my case <leader> is , so I type ,php to trigger the command.
Now for the command, bit by bit:
a<CR><ESC> : go into insert mode (after the cursor), insert a line break, go back into normal mode.
:.-1read <file><CR> : this enters the desired file on the line above the current line.
I<BS><ESC> : jump to the start of the line, delete line break, return to normal mode.
j0i<BS><ESC>l : Go down one line (to the remainder of the line that you were initially on), jump to the start, enter insert mode, delete the line break, return to normal mode.
l : position the cursor to the right of the pasted file (this just made the command work more like how you expect it to).
note
You have a choice of whether to paste before or after the cursor. I have chosen in this example to paste after the cursor because that is how the p command usually works to paste yanked text. Alternately, to paste before the cursor you should change the a at the start of the command to an i. You could use one of these exclusively, or you could bind them both to different but related key sequences. For example:
`nnoremap <leader>php i<CR><ESC>:.-1read $SNIPPETS/php<CR>I<BS><ESC>j0i<BS><ESC>l`
Could paste text before the cursor,
and :
`nnoremap <leader><leader>php a<CR><ESC>:.-1read $SNIPPETS/php<CR>I<BS><ESC>j0i<BS><ESC>l`
could paste text after the cursor. Or vice versa. I have made 'before the cursor' easier to trigger because I use it more often when pasting in-line.
other note
This solution is mainly useful if you're reading from a file that you expect to use often enough that it's worthwhile setting up a key mapping for it (ie reading a snippet from a file). This doesn't really help if you just want to read in a random files whenever since you won't have the key mapping ready.
Since it is very formulaic, I'm sure it would be possible to define a function that would take the file name as an argument and do the same thing though. I've never written a function in vimscript though so if someone who knows more feels like editing this answer to contain that solution - I urge them to do so!
" put this in your ~/.vimrc
" in insert mode press ,n
"
imap ,n <c-r>=expand("%:p")<cr>
Read more in wikia.

Commenting out a function with NerdCommenter

Is there a way to do this? I know you can do all the obvious ones like ,c and ,cs
But I don't think there's a binding for commenting out an entire function...
From anywhere inside the function, do:
va{,c<space>
off course, you can map this to something:
:map ,o va{,c<space>
so pressing ,o inside a function will comment it (or uncomment it if it is already commented).
It depends..
It depends on how the function is, and where you are.
public function test()
{
$name = "whatever";
$data = array(
'name' => $name
);
return $data;
}
Scenario 1: Cursor Line 1 at public function test()
Sequence: Vj%
V Start linewise visual mode
j Go down one line
% Go to matching closing bracket
Scenario 2: Cursor Line 3 at $name = "whatever"
Sequence: va{ok
v Start visual mode
a{ Arround bracket
o Exchange cursor from top to bottom of selection
k Go up one line
Then, comment as usual ,,c depending on your Nerd Commenter mapping.
There are no binding for commenting out the whole function (as far as i know). I think there are couple of ways you can achieve this - for example you can place cursor on the closing bracket, go to the visual line mode, press % key (and select additional line if you place opening bracket in new line) and then use \cc for example.
When I want to achieve this i use textobj-user and textobj-rubyblock (I am currently programming mostly in Ruby) plugins, which allow me to easily select block of code with var and expand it with ar. That's quite nice, because I don't need to go to the end keyword (in C that would be closing bracket), but I select whole function without moving cursor from the function's body. I have not tried this, but for you this plugin should work. That's not a solution with one binding, but it's quite quick too. I hope this will be usefull for you. :)

Resources