Dynamically replacing (or appending/prepending) to selection in Vim - vim

I have the following paragraph in a plain text file that I am viewing (and editing) in Vim:
The synthesis and secretion of estrogens is stimulated by follicle-stimulating hormone (FSH), which is, in turn, controlled by the hypothalamic gonadotropin releasing hormone (GnRH). High levels of estrogens suppress the release of GnRH (bar) providing a negative-feedback control of hormone levels.
I am creating cloze deletion flashcards out of the text in this text file (ie. fill in the blank questions) which I will then feed to a home-made flashcard program I've written. My format for a cloze deletion is as follows:
The synthesis and secretion of [estrogens] is stimulated by [follicle-stimulating hormone]
This would produce two flashcards (when the text file is parsed by my flashcard program):
The synthesis and secretion of [...] is stimulated by follicle-stimulating hormone
The synthesis and secretion of [estrogens] is stimulated by [...]
I would like to automate the creation of these flashcards using Vim. The manual option would be to write a '[' to the beginning of each cloze deletion and a ']' at the end, but this is tedious and I'd like to use Vim's automation abilities. Ideally, I would like to be able to:
select a region of text to clozeify
execute a macro on this text
This macro would:
prepend '[' to the selection
append ']' to the selection
and exit.
How would I achieve this using Vim? When I try to use Ctrl-R in Visual Selection Mode it doesn't seem to work.
Essentially, the replacement I would like to do is:
:%s/(CONTENT OF VISUAL SELECT)/[(CONTENT OF VISUAL SELECT)]/g

This is very easy to do with built-in commands:
v<motion>
c[<C-r>"]<Esc>
Breakdown:
v<motion> is what you already do to visually select the text to transform.
c cuts the visually selected text to the unnamed register and puts you in insert mode.
[ inserts an opening bracket.
<C-r>" inserts the content of the unnamed register.
] inserts a closing bracket.
<Esc> puts you back into normal mode.
With that in mind, you can record a macro of the edit above and play it back on any visual selection:
v<motion>
qq
c[<C-r>"]<Esc>
q
then:
v<motion>#q
Breakdown:
qq starts recording in register q.
q stops recording.
or create a visual mode mapping:
xnoremap <key> c[<C-r>"]<Esc>
If that's something you need to do often, you should probably take a look at Surround or Sandwich, which make all that considerably easier.
Reference:
:help c
:help i_ctrl-r
:help recording

Related

How to execute specific regex substitution on selected lines in visual mode in vim

I want to replicate the VS code feature of 'highlight and comment out code' (usually bound to keys SHIFT + /) in vim.
I can run :g//s/^/\/\/ / in normal mode to prepend // at the start of every line. I just want to put a constraint on this so it only applies the substitution to lines highlighted in visual mode.
Visually select all the lines (using V), then hit :.
This will give you :'<,'> which is the range of your visual selection.
Then you can add your vim command to it.
I would recommend the following method if you wish to not use plugins.
:'<,'>normal I//
Which is not a substitution.
If you want a really nice vim plugin that does this task in a vim manner, check out tpope's vim-commentary which is an essential in my opinion.
I can run :g//s/^/\/\/ / in normal mode to prepend // at the start of every line.
Well, that would be an unnecessarily complicated way to do it and your command wouldn't really work anyway.
:g// either matches nothing or it matches the previous search. What you want, here, is probably something like :g/^/ or :g/$/.
A simple substitution on the whole buffer would be much simpler and much faster:
:%s/^/\/\/ /
Using :help :global in this context provides no value (you want to operate on every line anyway) and is considerably slower (we are talking thousands of times slower)
You can use alternative separators to avoid all that backslashing:
:%s#^#// #
The last separator is not even needed:
:%s#^#// <-- there is a space, here
And the kicker: you can enter command-line mode from visual mode like you would do from normal mode, by pressing :. So you can simply make your visual selection, press :, and run your substitution:
v " enter visual mode
<motion> " expand the selection
: " press :
:'<,'> " Vim inserts the range covering the visual selection for you
:'<,'>s#^#// <CR> " perform your substitution

Why does vim use registers for almost every command?

I love the simplicity of composing commands that have semantic meaning. Like, for example cib reads like a sentence change in brackets - wonderful.
But why does vim need to copy the old contents into my clipboard? Nowhere in that command have I suggested I want to copy it and the problem goes much deeper.
dw diw etc all copy to the my clipboard/register as well. Why? It seems like this abandons the semantic value of these commands and I would say it is unexpected behaviour.
Am I using these commands wrong, or is there some way to completely disable this feature? Currently I have done a few remappings like this:
nnoremap dd "_dd
nnoremap cc "_cc
but I would like to not do that for every single possible combination of non-explicit copying.
By default, most of the commands you're talking about use the unnamed register, ". It sounds like you're dealing with the clipboard being overwritten for all these things too, which can be a symptom of setting clipboard to unnamed or unnamed_plus.
To go back to standard, you can probably do set clipboard=, if the output of set clipboard? is one of those two options.
*'clipboard'* *'cb'*
'clipboard' 'cb' string (default "autoselect,exclude:cons\|linux"
for X-windows, "" otherwise)
global
{not in Vi}
{only in GUI versions or when the |+xterm_clipboard|
feature is included}
This option is a list of comma separated names.
These names are recognized:
*clipboard-unnamed*
unnamed When included, Vim will use the clipboard register '*'
for all yank, delete, change and put operations which
would normally go to the unnamed register. When a
register is explicitly specified, it will always be
used regardless of whether "unnamed" is in 'clipboard'
or not. The clipboard register can always be
explicitly accessed using the "* notation. Also see
|gui-clipboard|.
*clipboard-unnamedplus*
unnamedplus A variant of the "unnamed" flag which uses the
clipboard register '+' (|quoteplus|) instead of
register '*' for all yank, delete, change and put
operations which would normally go to the unnamed
register. When "unnamed" is also included to the
option, yank operations (but not delete, change or
put) will additionally copy the text into register
'*'.
Only available with the |+X11| feature.
Availability can be checked with:
if has('unnamedplus')
I'll offer a dissenting view, and suggest that you are likely using Vim non-idiomatically. This is in no way unexpected behaviour. Are you using cib as a preparation for pasting, so that cib screws it up? Do vibp instead.
dw diw etc all copy to the my clipboard/register as well. Why? It seems like this abandons the semantic value of these commands and I would say it is unexpected behaviour.
d then p is the normal Vim idiom for cut-and-paste (i.e. move text). This is an operation I do every day, multiple times per day, and it would be really annoying if d did not also yank. You seem to think d is equivalent of Del on other text editors; it is rather the equivalent of ctrl-x (cut). To cancel this, you'd do "_d as you said; I find that I hardly ever need it.
As an advanced example, the default semantics of c and visual-mode p makes it trivial to exchange two objects; for example:
I drank all their food and ate all their whiskey.
Go to "drank", diw (delete the word and yank it), go to "ate", viwp (select a word and paste over it, yanking the previous content), ctrl-o to go back to where "drank" was and P (paste before cursor):
I ate all their food and drank all their whiskey.
(I also have a plugin which defines "function parameter" as a text object, so I use the same idiom in coding if I mix up, or refactor, the parameter order.)
The only thing I want to prevent more commonly is yank-on-paste in visual mode (so that I can paste the same content multiple times); for this, I use
xnoremap <expr> P '"_d"'.v:register.'P'
(from here). This only remaps P in visual mode (which is otherwise identical to p in visual mode). Neither p nor P outside visual mode yank, so it's a non-issue.

Duplicating line in Vim and appending few letters

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 :) ).

editing latex in vim : how to change text to math mode

I am using vim-latexsuite to edit a latex file. The text is originally from google doc and there are many math symbols not written in math mode.
I have to add $ before and after each symbol. But that is painful. (Search/Replace does not work because some equation patterns are complicated.)
Is there a way that allows me to visually select the symbols or equestions using Ctrl-V in visual mode, then after pressing the key, the $ can be automatically added before and after the visual selection?
I don't think there is any standard command for this, but you can use the surround.vim plugin to do this:
http://www.catonmat.net/blog/vim-plugins-surround-vim/
The command is csW$ to surround the current text with $
There actually is a standard command for this built into vim-latexsuite. See the vim-latex docs for macros here.
In addition the visual mode macros are provided:
`( encloses selection in \left( and \right)
`[ encloses selection in \left[ and \right]
`{ encloses selection in \left\{ and \right\}
`$ encloses selection in $$ or \[ \] depending on characterwise or
linewise selection
You can record a macro to do this.
With a visual selection, do this:
qq – record macro in register q
c – change the content of the visual selection
$$Esc – insert $$
P – paste the original text between the $s (note it's a capital P)
q – stop recording the macro
From then on, you can make your visual selection and just run #q.

When is Visual mode used in Vim?

I'm relatively new to the world of Vim. I've been learning my way around it but have yet to find a practical purpose to enter visual mode.
What are some scenarios when visual mode is especially useful?
Are there actions that can only be performed from within visual mode?
I use visual mode when I want to highlight a section of text. I start by typing v in standard mode, which then enables the visual mode. Then I use the arrow keys to move the cursor. This causes the text between my starting point and the current cursor location to be highlighted. Once you select a section of text like this, entering a command (e.g. search/replace) in command mode (by typing :) will only affect the selected area.
Another useful visual command is shift+v (visual line). This does the same as above, but it selects entire lines at a time instead of individual characters.
When you want to comment a block of text.
In command mode :
Shift + v
,ctrl +v,
j or k,
I , #(comment
character) and then Esc
Vim inserts the comment character to
the start of the block..
is when I am using Gvim, I find it much easier to copy data
to the clipboard through visual mode.
In command mode :
Shift + v
, j or k ,
" , +
,y
Here + is the clipboard
register
This to me is much more legible that using markers
is for manual indenting
Shift + v,
Shift + > for
moving to the right.
Shift + < for
moving to the left. .
repeats
this is fun :-)
One of the nice things about visual mode is that, because of Vim's focus on modality, you can perform most of the commands that you are used to (such as search/replace with :s, d to delete text, or r to replace text) while also seeing exactly what will be affected -- this allows you to determine the exact scope of whatever you are doing.
Furthermore, as someone else mentioned, you can easily insert a prefix (like a comment character or, say, & for alignment or \item in LaTeX) by selecting the first character of each line in visual block mode (ctrl+v), pressing I to insert before the first character, typing in whatever you want to insert, and then Escing back to normal mode.
The last kind of visual mode is visual line (Shift+v), which allows you to quickly select a number of lines. From there, you can change their indentation using > or < (prefix this with a number to indent by that many tabs), use d or y to delete or copy those lines, use zf to create a new fold from those lines, or use any other selection-based command.
Finally, there are a lot of other cool things you can do with visual mode, including gv to reselect your last visual[line/block] mode selection, gU to convert a visual selection to uppercase or gu for lowercase, and many more.
In addition to the other (great) answers, it's an easy way to define scope for an action. For example, to limit a search & replace to a specific method...
Say you have this code:
function foo() {
abc();
while (1) {
def();
abc();
}
}
You can place the cursor on any of the braces or parentheses and press v, %, :, s/abc/xyz/g and your search & replace will have a defined scope in which the action will occur.
Visual mode is useful if you want to apply a command to a section of text that isn't easily described as a primitive movement command. You can select some text in visual mode with a complex sequence of movements and then apply a command to that selection.
I often find myself using visual-block mode (Ctrl + v) more than any of the other visual modes.
You can easily remove indentation, comments, etc. once you are aware of this mode. In my experience, this is often faster than figuring out how to form an equivalent search-and-delete statement.
You can also add indentation (or comments as Cherian stated) by selecting a block of text and pressing I, typing whatever you want to add, and pressing Esc (note: you may need to redraw the screen (e.g. by moving the cursor) to see the effects of this).
I haven't seen the following mentioned, probably because they're subtle.
1 - Less hassle with the unnamed register
Whenever you copy (yank) some text, and then want to d to change some other text, e.g., diw to "delete inner word," Vim will place the deleted text into the unnamed register. Then if you try to paste, it will just paste the deleted text right back unless you do "0p to paste from the 0 register.
But with visual mode, you can just do something like viwp and don't have to mess with registers.
So, for comparison, to copy and replace inside some parens:
yiw -> move somewhere -> vi(p
vs
yiw -> move -> ci(<C-r>0p
yiw -> move -> "_di(p
yiw -> move -> di("0P
Note: this also works for deleting text and pasting it back over a text object. See here.
2 - Jumping to parts of a text object
If you want to jump to the beginning or end of a text object, you can select it in visual mode and press o. For example, va" to select anywhere inside quotes, and then press o to jump to the matching quotes, kind of like % for matching brackets.

Resources