Related
I am editing a dictionary in a text file, containing Russian words - one word per line.
Some nouns are missing their derivatives, which are usually the same word appended by few more letters - in 6-7 variations as shown in this screenshot:
In Vim I would like to put the cursor in the first column and scroll down line by line. And when I recognize a noun, I'd like to press some (as few as possible!) keystrokes to take that word, copy it in separate lines and append the letters.
I can get rid of the duplicates by issuing %sort u later.
If I could run that command on the whole file it would be something like:
%s/\(.\+\)$/\1^M\1а^M\1ам^M\1ами^M\1ах^M\1е^M\1ном^M/
Do you please have an idea, how to create such a "macro" in Vim?
There are a couple of ways that you can handle this. You can create a macro or you can create a map. Either can be done while running VIM. Either can be placed in another file (your .vimrc, for example, or a file with bindings specific to this project) and sourced when needed.
I will also give you a bit more advice with regular expressions: if you are writing something particularly complex, you can greatly decrease the number of \s needed by starting the regular expression with \v (i.e., :s/\v([0-9a-f]+\s)/0x\1/g).
Creating a Macro in VIM
You can start a macro in VIM by pressing q in Normal mode, followed by the key that you wish to use for the macro. You can then invoke the macro by pressing # followed by the macro's letter. Press q again in Normal mode to stop recording.
You can therefore enter this macro as follows (using the q register):
qq:s/\(.\+\)$/\1\r\1а\r\1ам\r\1ами\r\1ах\r\1е\r\1ном\r/Enterq
Then, when you are on a line and you want to run this command, enter #q from Normal mode.
Storing a macro in a file and sourcing it
When you created a macro in the last step, what you were actually doing was setting the q register. You can check this by entering the registers in command mode. You can instead set this macro in your .vimrc file as follows and it will be available every time you start VIM.
Create the file you want to store this macro in (:new).
Add the following line to the file:
let #q=":s/\\(.\\+\\)$/\\1\\r\\1a\\r\\1b\\r\\1ам\\r\\1ами\\r\\1ах\\r\\1е\\r\\1ном\\r/^M"
(If you yank the line and paste it in VIM with Ctrl+R", there will be a proper ^M character at the end of the line. You'll need to do some manual editing to make sure that it's inside the quotes. Alternatively, you can enter Ctrl+VCtrl+M to enter the ^M character.)
Save the file (:w testmacro.vim).
Source it (:so % or :source %).
Test your macro by typing #q on one of the lines you'd like to do this to.
Later, you will be able to load this macro by running :so testmacro.vim.
Create a Mapping
You can instead create a mapping. The following mapping copies the last word in a given line, pastes it onto the following six lines, and then appends to each of the given lines.
nnoremap <c-j> yy6pAа<esc>jAам<esc>jAами<esc>jAах<esc>jAе<esc>jAном<esc>j
n at the beginning of "nnoremap" indicates that it only functions in Normal mode.
noremap means that this command won't engage in any recursive remapping (whereas with nmap, this could happen).
<c-j> maps to Ctrl+J
yy6p yanks the line and pastes it 6 times.
Aa<esc>j appends to the end of the current line, enters the text (in this case a), exits Insert mode, and moves down a line.
You can enter this command in VIM's command mode or you can store it in a file and load it with the :source command.
Combining Registers with Mappings
You can access a register in your mappings. This means that if you know that entering a given replacement regex will do what you want, you can save that in a register and then enter your command on the current line.
To do this, enter the following commands in a file and then source it:
nnoremap <c-i> :<c-r>f<cr>
let #f="s/\\(.\\+\\)$/\\1\\r\\1a\\r\\1b\\r\\1ам\\r\\1ами\\r\\1ах\\r\\1е\\r\\1ном\\r/^M"
Now you can enter Ctrl+I to run the replacement regex in register f on the current line.
Alternatively, dedicate a few registers to the purpose - let's say a-f.
nnoremap <c-l> yy6p$"apj"bpj"cpj"dpj"epj"fpj
let #a="a"
let #b="ам"
let #c="ами"
let #d="ax"
let #e="e"
let #f="ном
In this case, we're using the ability to press " and the name of a register before hitting a command that uses it, such as paste.
You can record macros by pressing q in the escape mode. For example,
position your cursor on the noun you want to edit.
press qa to start recording macro and store it in register a (other alphabet and digits may also be used for registers) .
do whatever general actions you want to do (copy line, paste, append letters, etc. as in you have tried to show in your search string).
once you are done with the changes, in escape mode press q again.
Your macro is now created in register a. Whenever, you want to repeat your key sequences, just press #a.
Note that you can do anything in recording mode, including any kinds of commands, insertions, cursor movements, and so on. For more information on macros and related options, check out Vim help :h complex-repeat.
Vim registers are shared as place holders for both macros and yanked test; this feature allows you to even save and edit your macros in a file. See this question for details.
Here is a map solution - which copies the line into a buffer and then pastes using p.
The A appends at the end of the line
map <F2> 0dwpo<esc>pAa<enter><esc>pAam<enter><esc>pAax ...etc
If your goal is, when your cursor on a special word, and press something, vim will append different "suffixes" (I hope I used the right word, but you knew what I mean). You could go macro (q). However since you have already written the :s command, you could create a mapping using that command do the same, and it would be shorter.
in command line, you can get the word under cursor by pressing <c-r><c-w>. so you could try:
nnoremap <leader>z :s/<c-r><c-w>/& & &..../<cr>
I didn't write the & & &... part, since I don't know (never tried, I don't have vim under windows. I don't even have windows) if the line break \n could be used here under windows. & means the whole matched part, which in this case is the word under your cursor.
So you just move your cursor to the word, type <leader>z, vim will do the job for you. (if the replacement part is correct :) ).
The command p pastes below the cursor and P pastes above the cursor. What's the command to paste in the line where cursor is?
This all depends on the type of data in the register you're pasting. If the data is line-oriented data (yanked with yy for instance) it will be pasted as a whole line above or below the cursor. If the data is character-oriented (yanked with e.g. y2w) then it will be pasted at or before the cursor position in the current line.
See :help linewise-register for more info on the interaction between the type of register and the put command.
The Edit menu in gvim lists the following:
Paste = "+gP
Put Before = [p
Put After = ]p
If you're running vim in Windows, you can do the following to get Ctrl+C and Ctrl+V to work as expected:
source $VIMRUNTIME/mswin.vim
behave mswin
If you want to keep the current line as it is, you either paste above or below the line.
If you want to overwrite the current line you'll have to delete it first, which means that the following line takes its place, then paste above the new current line.
There are more than one way to do it:
"_ddP
"_dd deletes the whole current line in the "black hole register", the following line is now the current line.
P puts the content of the unnamed register above the current line.
Vp
V puts you in VISUAL LINE mode and selects visually the whole current line
p replaces the selection with the content of the unnamed register
S<C-r>"
S deletes the content of the current line and puts you in INSERT mode
<C-r>" puts the content of the unnamed register
The two last options have an interesting side effect: the content of the previous line is put into the unnamed register which makes it impossible to do multiple pastes with the same content.
Luckily, you can work around this situation:
The "black hole register", mentioned in the first solution works, well… like a black hole. Whatever you put into it disappears forever so you can continue using p and P with some degree of confidence that the unnamed register is still the same from paste to paste.
Vim gives you access to 26 alphabetic registers that you can use to save macros or… paste stuff repeatedly.
Taking the second solution as a starting point, you start by yanking a whole line into register "a with "ayy then you do V"ap on another line.
But all of the above assumes that the text you want to paste is an actual line. Vim makes the difference between "line-wise" and "character-wise" : it won't let you paste a line in a character-wise context or the other way around.
Yanking a whole line with yy keeps its line-wiseness or character-wiseness and you won't be able to p between two characters on a same line. For that you need to make sure that what you yank won't be interpreted as line-wise by Vim. For example, let's assume you are on the first character of the first line and want to yank ipsum dolor and put it at its normal place between lorem and sit:
ipsum dolor
lorem sit amet
You should type "ayee to put your yanked text in register "a, place the cursor where needed and type "aP.
To paste in insert mode you just press Control+R. Then enter the register, e.g. Shift++.
To paste in command mode, you press P, however you've to make sure your line doesn't have a new line character (e.g. yanked by 0v$hy), otherwise it'll appear above the cursor.
The same for visual mode, see: How to paste a line in a vertical selection block? at Vim SE
You can use D to delete from current cursor position to the end of line, and the p to the new cursor position.
That is to cut and paste a whole line use ^D and p.
Shift + v will select the entire line, but you don't want to do that. Instead, press CTRL + v from the beginning of the line which will select by character, then $ to select to the end of the line. yank y and paste p.
I needed to "cast" register contents into a certain (characterwise / linewise / blockwise) mode so often, I wrote the UnconditionalPaste plugin for it. It provides gcp, glp, etc. alternatives to the built-in paste commands that force a certain mode (and by now several more variations on this theme, like pasting with joined by commas or queried characters).
With it, you can just use gcp / gcP to paste after / before the cursor position, regardless of how you've yanked the text.
(I know this thread is old, just leaving this and hope this may help someone)
Inspired by #wbg's comment above regarding deleting the line feed, I added these to my mappings:
nnoremap <leader>p :let #"=substitute(#", '\n\+$', '', '')<CR>p
inoremap <leader>p <esc>:let #"=substitute(#", '\n\+$', '', '')<CR>pa
This is useful when I have a file with some SQLs (line by line) and I have to yank into the code.
vp that's how, type vp in normal mode
How is this not an answer to a 10 year old question, stackoverflow slip'n?
The character under the cursor will be replaced by the the put
To help with and many others scenarios, I've mapped rr for the ability to quickly add a space, or some other 1-off character.
noremap rr i<space><esc>r in my ~/.vimrc
divide the line into 2 wherever you want to insert
paste the section between them
merge the 3 lines with j as described here (Delete newline in Vim)
works, but tedious, and had to think about, look it up
=> vi and emacs are garbage software
I'm not sure there is one. I tried to find documentation and ran across the following three documents:
Vim commands cheat sheet
Vim editor commands
Mastering the VI editor
Unfortunately, all three only have the two commands that you list. Particularly, the third link states that The commands to paste are p and P...
If I've selected some text in visual mode, how do I insert the selected text into the command line?
For example, if I want to search for the currently selected text, I could use y/<c-r>"… But is there some way of doing it without first yanking the selected text?
Edit: A better example, as searching while in visual mode would expand the selection: if I've got part of a file name selected, and I want append to that name then open it in a new editor.
I have remapped : in visual mode to solve this problem. With following mapping I can paste selected text to the command line and b - onus - move the cursor to the leftmost position:
vnoremap : y:<C-r>"<C-b>
One small drawback I can see - pressing : now cancels the selection.
After activating visual mode and selecting some text, if I hit / to search forward and then press <C-R>*, I get the selected text inserted into the command line.
Another way (at least in Linux) is to press <S-Insert>, which will insert the contents of the current selection in X11 (e.g. select something in firefox and you can <S-Insert> in any other application to copy that selection; again, at least in Linux).
Keep in mind that with your specific example, after you insert some text after the / command, your visual selection will expand to include the next occurrence of whatever it is searching.
Edit: I was assuming GVim, which copies the visual selection to the X11 selection buffer (see :help x11-selection for more info).
If you are using Vim inside a console, then I think (but could be wrong) that your best option is to select the text you want with the mouse while pressing Shift down, and then use <S-Insert> to copy that text into the command line. This works in Linux and probably in OSX too; I don't know about Windows, sorry.
Put copy and paste code into vimrc config file.
Reopen vim editor.
Select text (e.g. using v)
Enter command mode using :
Selected text can now be pasted to command line using Ctrl-p
The selected text will have special characters escaped ready for use in regex.
Credits:
Based on idea by ierton (on this page)
Most of code taken from bryan kennedy
Vim search and replace selected text
" Escape special characters in a string for exact matching.
" This is useful to copying strings from the file to the search tool
" Based on this - http://peterodding.com/code/vim/profile/autoload/xolox/escape.vim
function! EscapeString (string)
let string=a:string
" Escape regex characters
let string = escape(string, '^$.*\/~[]')
" Escape the line endings
let string = substitute(string, '\n', '\\n', 'g')
return string
endfunction
" Get the current visual block for search and replaces
" This function passed the visual block through a string escape function
" Based on this - https://stackoverflow.com/questions/676600/vim-replace-selected-text/677918#677918
function! GetVisual() range
" Save the current register and clipboard
let reg_save = getreg('"')
let regtype_save = getregtype('"')
let cb_save = &clipboard
set clipboard&
" Put the current visual selection in the " register
normal! ""gvy
let selection = getreg('"')
" Put the saved registers and clipboards back
call setreg('"', reg_save, regtype_save)
let &clipboard = cb_save
"Escape any special characters in the selection
let escaped_selection = EscapeString(selection)
return escaped_selection
endfunction
" Start the find and replace command across the entire file
vmap <leader>z <Esc>:%s/<c-r>=GetVisual()<cr>/
" When in visual mode,
" before command mode is entered by using :
" Put the contents of any selected text into
" the default register
" leave the text highlighted.
" Based on ierton - https://stackoverflow.com/questions/4878980/vim-insert-selected-text-into-command-line
vnoremap : "pygv:
"Map ctrl-P to paste escaped contents of default register in command mode
" Based on bryan kennedy - https://stackoverflow.com/questions/676600/vim-search-and-replace-selected-text
cnoremap <C-P> <c-r>=GetVisual()<cr>
I know this may or may not help you, but type !command from within vim.. It's not copy and paste, but if you're using ssh - it will at least let you view your buffer(s) while you're typing out your command.
ex: !make
It really all depends on what environment you're in..
If you're using putty from windows, you can actually highlight and copy text from it(configurable as well within putty) and paste into either another putty session or another window(if using screen or tmux).
If you're actually on the box and have a graphical environment, copy & paste should be fairly easy(so I assume you're not in this position).
Hope it helps, sorry if it doesn't.
For pasting on the vim command line:
first copy the selected text
open command line :
use Ctrl-r " for pasting
I found the solution. When you press : in visual mode instead of normal ":" you have there ":'<,'>". So you need to erase this to write command as usual.
For expanding to selected text <C-r>* works pretty well.
vnoremap <M-8> :<BS><BS><BS><BS><BS>NGrep <C-r>*<CR>
If you want to edit command before launching it just remove trailing <CR>.
When I open a new line (via 'o') my cursor jumps to a correctly indented position on the next line. On the other hand, entering insert mode while my cursor is on a blank line doesn't move my cursor to the correctly indented location.
How do I make vim correctly indent my cursor when entering insert mode (via i) on a blank line?
cc will replace the contents of the current line and enter insert mode at the correct indentation - so on a blank line will do exactly what you're after.
I believe that the behaviour of i you describe is correct because there are many use cases where you want to insert at that specific location on a blank line, rather than jumping to wherever vim guesses you want to insert.
Well this actually wasn't as bad as I thought it would be. One way to enable this is to add the following to your ~/.vimrc
"smart indent when entering insert mode with i on empty lines
function! IndentWithI()
if len(getline('.')) == 0
return "\"_ccO"
else
return "i"
endif
endfunction
nnoremap <expr> i IndentWithI()
It simply checks for an empty line when you hit 'i' from insert mode. If you are indeed on an empty line it will delete it and open a new one, effectively leveraging the working 'open line' behavior.
Note: "_ before the cc makes sure that your register doesn't get wiped
On an empty line, to enter insert mode correctly indented, you can simply use s.
Note that s is a synonym for cl, so if you're not actually on an empty line, it'll end up deleting a single character and not indenting. In that case, you're better off using cc, as sml suggested some 18 months ago. But I've frequently improved my score at VimGolf by using this shortcut, so thought I'd mention it. ;)
In Vim, how do I insert characters at the beginning of each line in a selection?
For instance, I want to comment out a block of code by prepending // at the beginning of each line assuming my language's comment system doesn't allow block commenting like /* */. How would I do this?
Press Esc to enter 'command mode'
Use Ctrl+V to enter visual block mode
Move Up/Downto select the columns of text in the lines you want to
comment.
Then hit Shift+i and type the text you want to insert.
Then hit Esc, wait 1 second and the inserted text will appear on every line.
For further information and reading, check out "Inserting text in multiple lines" in the Vim Tips Wiki.
This replaces the beginning of each line with "//":
:%s!^!//!
This replaces the beginning of each selected line (use visual mode to select) with "//":
:'<,'>s!^!//!
Note that gv (in normal mode) restores the last visual selection, this comes in handy from time to time.
The general pattern for search and replace is:
:s/search/replace/
Replaces the first occurrence of 'search' with 'replace' for current line
:s/search/replace/g
Replaces all occurrences of 'search' with 'replace' for current line, 'g' is short for 'global'
This command will replace each occurrence of 'search' with 'replace' for the current line only. The % is used to search over the whole file. To confirm each replacement interactively append a 'c' for confirm:
:%s/search/replace/c
Interactive confirm replacing 'search' with 'replace' for the entire file
Instead of the % character you can use a line number range (note that the '^' character is a special search character for the start of line):
:14,20s/^/#/
Inserts a '#' character at the start of lines 14-20
If you want to use another comment character (like //) then change your command delimiter:
:14,20s!^!//!
Inserts a '//' character sequence at the start of lines 14-20
Or you can always just escape the // characters like:
:14,20s/^/\/\//
Inserts a '//' character sequence at the start of lines 14-20
If you are not seeing line numbers in your editor, simply type the following
:set nu
Another way that might be easier for newcomers:
some█
code
here
Place the cursor on the first line, e.g. by
gg
and type the following to get into insert mode and add your text:
I / / Space
// █some
code
here
Press Esc to get back to command mode and use the digraph:
j . j .
// some
// code
//█here
j is a motion command to go down one line and . repeats the last editing command you made.
And yet another way:
Move to the beginning of a line
enter Visual Block mode (CTRL-v)
select the lines you want (moving up/down with j/k, or jumping to a line with [line]G)
press I (that's capital i)
type the comment character(s)
press ESC
This adds # at the beginning of every line:
:%s/^/#/
And people will stop complaining about your lack of properly commenting scripts.
If you want to get super fancy about it, put this in your .vimrc:
vmap \c :s!^!//!<CR>
vmap \u :s!^//!!<CR>
Then, whenever in visual mode, you can hit \c to comment the block and \u to uncomment it. Of course, you can change those shortcut keystrokes to whatever.
Yet another way:
:'<,'>g/^/norm I//
/^/ is just a dummy pattern to match every line. norm lets you run the normal-mode commands that follow. I// says to enter insert-mode while jumping the cursor to the beginning of the line, then insert the following text (two slashes).
:g is often handy for doing something complex on multiple lines, where you may want to jump between multiple modes, delete or add lines, move the cursor around, run a bunch of macros, etc. And you can tell it to operate only on lines that match a pattern.
To insert "ABC" at the begining of each line:
Go to command mode
% norm I ABC
For commenting blocks of code, I like the NERD Commenter plugin.
Select some text:
Shift-V
...select the lines of text you want to comment....
Comment:
,cc
Uncomment:
,cu
Or just toggle the comment state of a line or block:
,c<space>
I can recommend the EnhCommentify plugin.
eg. put this to your vimrc:
let maplocalleader=','
vmap <silent> <LocalLeader>c <Plug>VisualTraditional
nmap <silent> <LocalLeader>c <Plug>Traditional
let g:EnhCommentifyBindInInsert = 'No'
let g:EnhCommentifyMultiPartBlocks = 'Yes'
let g:EnhCommentifyPretty = 'Yes'
let g:EnhCommentifyRespectIndent = 'Yes'
let g:EnhCommentifyUseBlockIndent = 'Yes'
you can then comment/uncomment the (selected) lines with ',c'
Mark the area to be comment as a visual block (<C-V)
and do c#<ESC>p
change it to "#"
put it back
If you do it often, define a short cut (example \q) in your .vimrc
:vmap \q c#<ESC>p
In case someone's multi-line-selection is actually a paragraph, there is no need to manually select the lines. vim can do that for you:
vip: select and mark the whole paragraph
shift-i: insert text at line beginning
escape: leave insert mode/enter normal mode [line beginnings still selected]
escape: unselect line beginnings
Mapping of most voted answer:
1st visual select the desired lines, then execute <leader>zzz, which values:
vnoremap <leader>zzz <C-V>^I-<Space><Esc>
<C-V> to enter visual mode
^ goes to start of line ( or use '0' to 1st non blank)
I to insert in block mode
-<Space> to insert '- ' (for example, edit as you need)
<Esc> to apply same insert to all visual block lines
Or of last visual selection from normal mode:
nnoremap <leader>zzz gv<C-V>^I-<Space><Esc>