Vim: Easy way to convert recorded macro into let - vim

I want to save a certain macro permanently so that I can replay it in future sessions.
For instance, I record the macro which surrounds selected words with ** (like **this text is strong**):
Switch to the visual mode
Select some words
Start recording "a"
Press c, **, Ctrl-r, ", **, Ctrl-; (to switch to the normal mode); and
Stop recording.
From the next time, I can just select words and press #a to replay these actions.
Now I enter :reg a and see this output:
--- Registers ---
"a c**^R"**^[
How can I define this using the :let function so that I can add this to .vimrc and make this macro permanent?
:let #a='c**^R"**^['
didn't work.

The ^R and ^[ in the output of :reg a are literal control codes, not ^ followed by R or by [. Usually, Vim uses a special color to hint at that difference.
You can do either of two things…
In your vimrc, type out the macro directly, using :help i_ctrl-v to insert the literal control codes. That is, press <C-v> then <C-r> to insert a literal ^R:
let #a = 'c** " type this out
<C-v><C-r> " press <C-v><C-r> to insert ^R
"** " type this out
<C-v><Esc> " press <C-v><Esc> to insert ^[
' " type this out
<Esc> " leave insert mode
In your vimrc, insert the register directly between the quotes with :help i_ctrl-r:
let #a = '
<C-r>a
'
<Esc>
Note that it doesn't protect the register in any way so #a can be overwritten accidentally. A mapping, the right hand side of which is a macro, seems safer to me:
" again, use <C-v><C-r> to insert `^R`
xnoremap <key> c**^R"**^[
" or use the angled brackets notation
xnoremap <key> c**<C-r>"**<Esc>

Related

vim vnoremap: E488 Trailing characters

I'm using vim to program and I just want to make a shortcut for comment.
Here is how I set in .vimrc:
vnoremap <F7> :%s/^/\/\//g
I just want to add // in front of each selected line. However, when I press <F7> and press Enter in visual mode, I get an error:
E488 Trailing characters
Note that when you press F7 it just simulates pressing all the keys in the string. As soon as it presses : it gets into a state
:'<,'>
When it then types in all the rest of your command it gets into:
:'<,'>%s/^/\/\//g
Which is meaningless (% after '<,'> doesn't make sense). If you just remove % from your command, it will already work. Even better, add <CR> at the end so that you don't need to press Enter:
vnoremap <F7> :s/^/\/\//g<CR>

Function to Comment Multiple Lines Vimrc

So I currently like this solution to commenting multiple lines in vim:
Press CTRL-v (to go into Visual Block mode)
Select the lines you want to comment
Press Shift-i (to go into Insert mode)
Type whatever comment characters your language uses
Press ESC ESC (pressing the escape key twice makes the results appear faster)
But I would like some help mapping these steps into my vimrc file.
I currently use the following to comment lines out:
vnoremap ;/ <C-v>0I// <ESC>
For those who want an explanation of what the command does:
You basically type ;/ when you're in Visual mode to use this (Visual, Visual Line, and Visual Block mode all work since the <C-v> part forces you into Visual Block mode, which is correct).
The 0I part will put you in Insert mode at the beginning of the line.
The // <ESC> part will insert the comment characters // and put you back into Normal mode.
The part I need help with is uncommenting the lines. How do I write a function in my vimrc that will basically let me toggle the // characters?
Ideally, the solution would involve the following:
Selecting the lines
Pressing ;/
If there are NO // characters then it will insert them
If there ARE // characters then it will remove them
Put this in your .vimrc file:
vnoremap <silent> ;/ :call ToggleComment()<cr>
function! ToggleComment()
if matchstr(getline(line(".")),'^\s*\/\/.*$') == ''
:execute "s:^://:"
else
:execute "s:^\s*//::"
endif
endfunction
check the Commentary plugin. It allows to have one binding for all languages.
Pretty easy with python script
function! Comment()
python3 << EOF
import vim
r = vim.current.range
line = vim.current.buffer[r.start]
if line.startswith('// '):
vim.current.buffer[r.start] = vim.current.buffer[r.start].replace('// ', '')
else:
vim.current.buffer[r.start] = '// ' + vim.current.buffer[r.start]
EOF
endfunction
" ctrl slash
noremap <C-_> :call Comment()<CR>

Insert a whitespace in normal mode (used in insert mode)

Based on the idea of quick command in insert mode I want to insert my OS clipboard when I am in the insert mode. To make that happen as I want, I have to add a whitespace in the inoremap call, but I do not know how?
This is done with
inoremap VV <Esc>"+gP
Using this:
"vim" is in the OS clipboard
Typing in insert mode "work smart with VV"
leads to the result
work smart withvim
What I want is a whitespace between with and vim
work smart with vim
Any suggestions?
Your issue is caused by the P in "+gP and by the fact that leaving insert mode moves the cursor one character to the left, on the <space>.
P pastes before the cursor so your mapping pastes before the <space>. Changing the P to p should "fix" your problem, in a superficial way.
Here is a more solid alternative that inserts the content of the clipboard register right after the cursor without leaving insert mode:
inoremap VV <C-r>+
Well… what about simply using <C-r>+?
Working around a side effect (here, pasting after the cursor) is not the same as avoiding that side effect (here, not leaving insert mode to begin with). Guess which one is the right approach? ;-)
Use
inoremap VV <Esc>"+gp
P places the clipboard before cursor, p after cursor.
Option 1.
inoremap VV <C-R><C-o>+
Ctrl-R tells vim to insert the contents of a register, and + is the OS clipboard register. It inserts the clipboard contents as if you typed them. The additional <c-o> makes the register contents get inserted literally, so that things like <esc> or ^H (backspace) aren't interpreted like you typed them, but are inserted as text.
Option 2.
inoremap VV <C-o>"+gp
C-o tells vim to go to normal mode for just one command, so you don't need to add <Esc> at start, or i at the end.

How do I search for the selected text?

How do I search for the selected (with v and y) string? I usually search with /, but I cannot paste the selected string after /.
In insert mode you can use CTRL-R to insert the contents of Vim registers. By default, copied text gets put in the unnamed register ", so to insert that text you would type <C-R>" in insert mode. The search prompt uses Command-line mode which has its own
CTRL-R that works almost identically to the one in Insert mode.
So if I just yanked the text foo, typing /<C-R>" would search for the text foo once I press enter.
:set hls
:vmap * y:let #/ = #"<CR>
set hls (hight light search)
v => hjkl (select something)
press *, copy selected text to reg "
set content of reg / as "
press n/N to navigate
I have this mapping defined in my vimrc, it maps * to defining the search pattern as what is currently highlighted (escaping all potential dangerous characters, and converting a space in what is highlighted to any sequence of spaces)
xnoremap * :<C-U>let old_reg=getreg('"')|let old_regtype=getregtype('"')<CR>gvy/<C-R><C-R>=substitute(substitute(escape(#", '/\.*$^~['), '\s\+', '\\s\\+', 'g'), '\_s\+', '\\_s*', 'g')<CR><CR>gV:call setreg('"', old_reg, old_regtype)<CR>:let v:searchforward=1<CR>
In order to use it, start visual mode with v, and then highlight what you want to search and press * not y.
Of course you can map # to search backwards (exactly the same except that v:searchforward should be set to 0.
If you only care about searches, you can use the cheat method I use. Yank a word via v or y+w, then issue the command
:%s//XYZ/gc
This will search for the last searched word. Then when you find it, it will ask for confirmation to replace with XYZ, and all you have to do is hit q to quit.
First yank the highlighted text using y. Then
/
Ctrl + r
"
Above commands will paste what you have yanked after the /. Then press ENTER

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.

Resources