How to use an external command in Vim to modify the selection - vim

Something I've found useful in other editors is the ability to:
take the selected text
run an external command and pass the selection to its stdin
take the external commands stdout and replace the current selection with it.
This way you can write useful text tools which operate on the selection using any language that can do basic io.
How can this be done with vim?
(Directly in the command line, or via a key binding?)

:'<,'>!command
'<,'> represents the (linewise) visual selection and is automatically inserted when you hit : and have something selected.
Example:
If you select a line containing:
print("Hello!")
and run the Vim command:
:'<,'>!python
the text will be replaced with Hello!.
If you want to set this to a key-binding (F5 to evaluate for example)
vnoremap <F5> :!python<cr>

Related

How to document all commands that I used in Vim editor in a special file?

I need to document all commands that I used to modify text using Vim editor. When I am in the terminal and need to save all my input in a file I usually write:
history > ~/some_file.txt
However, I am not sure how to do it while using vim. Can you tell me?
Any output can be redirected with :redir. So
redir >~/vim.history|silent history|redir END
Will redirect the output of :history to the file ~/vim.history. Here silent is used to prevent a -- More -- prompt.
You could also put the history into the current buffer with
:put =execute(':history')
Note that Vims history is limited to 50 entries by default (see :help 'history).
Use startup option -w. From the docs:
All the characters that you type are recorded in the file "scriptout", until you exit Vim. This is useful if you want to create a script file to be used with "vim -s" or ":source!".
Press qx, which causes Vim to start recording your keystrokes.
Press q to finish recording.
Move your cursor to wherever you would like Vim to paste the record it has just made.
Press "xp to paste the record.
The x identifies a buffer. Buffers y, z and so on also exist, so you can use a different letter than x if you wish.
Nothing requires you to paste the record into the file you were editing when the record was made, incidentally. To paste into a different file, give the command :tabedit name-of-different-file, press [Enter], and then press "xp to paste. (Since :tabedit opens the second files in another tab, you can then press gt to toggle between the two if you wish.)

Break out from Vim insert mode when pasting

Can one put control characters into a text so that when I copy and paste it in Vim it exits insert mode and does something nasty in command mode?
The short answer seems to be "yes". I was able to put the following in my clipboard:
hello<Escape>:!date<CR>
and when I pasted it into vim while in insert mode hello was typed and then the shell opened up and the date command was run.
Obviously if I can run the date command in the shell I can do much more nasty stuff.
To get that string in my paste buffer I opened vim and typed hello<C-V><Esc>:!date<C-V><Enter>. I then had to save that file, open it with Kate and copy the contents that way (copying from vim didn't preserve the control characters).
That depends on the environment, and the Vim command used.
Graphical GVIM can differentiate pastes from typed keys, but in the terminal, this is not (generally) possible. That's why Vim has the 'paste' and 'pastetoggle' options, to tell Vim what is expected. Despite that, if the character stream contains a key like <Esc> that switches modes, Vim will do so.
Instead of pushing text into Vim, it is safer to pull with Vim's put command: "*p. There, special characters like <Esc> will be inserted literally into the buffer; Vim won't switch modes here. The only Vim command that interprets register contents as typed (and therefore is susceptible to mode switch commands) is i_CTRL-R. To avoid that, one should use any of the other command variants, e.g. i_CTRL-R_CTRL-R.
summary
Pull text into Vim instead of pushing it; if you avoid the i_CTRL-R command (or neuter it by remapping it), this is safe. Additionally, the :registers command allows you to inspect all contents before pasting.

Editable vimgrep string in command line

I use vimgrep a lot to navigate in files and usually use the last search from the history to modify the search pattern and run it again.
Is there a way to display in the command line an editable string like the one below, with the cursor already positioned between the two search pattern slashes (and the pattern being empty)?
:vimgrep // **/*[ch]|copen
I don't want to use a constant mapping (like the one at this vim tip) since I want to be able to add/change options (\c etc.).
I'd recommend using the command-line window for this (q: opens it from normal mode), since you
can edit the command with the regular normal mode keystrokes (and you get syntax highlighting too).
You can also move around in your history just like in a normal buffer. So ?vimgrep<Enter>nnn... will search for and move you to all your old vimgrep commands.
Just hit <Enter> as normal when you are done editing, or :q<Enter> to abort the command and quit the window like you would any other.
Finally, here's a mapping to quickly bring up your empty vimgrep template in the command-line window.
:nnoremap \v q:ivimgrep<Space>//<Space>**/*[ch]<Bar>copen<Esc>F/;i
Reference: :help cmdline-window

How to filter visual selection?

Suppose we have some nice bunch of text:
Hello world
and we select the world in visual mode. Then we could filter the visual selection using a shiny command like this one:
:'<,'>!echo foobar
However, that would replace the entire line with foobar instead of just the world. Why is this, and how can we just replace the world?
The :! filter command always works on entire lines (this is as old as the original vi, embedding Ex commands that start with :), and the '<,'> range also only specifies lines.
You can use the venerable vis plugin to achieve your result; it offers a :B command that limits the following command to the visually selected text.
:'<,'>B !echo foobar
The plugin works for all kind of Ex commands; for :substitute within the selection you can also use the special \%V atom, though.

How do I repeatedly search & replace a long string of text in vim?

I'm aware of the vim replace command, which is of the form, eg:
:%s/old/new/gc
But what if either of these strings is long? How can I use something like visual selection mode, the clipboard or vim registers instead of having to type the old/new text in?
You can use q: to bring up a command-line window. This lets you use all the vim editing commands to edit the vim command line, including p to paste. So, you could copy the text into a register, paste it into the command line window, and execute it that way.
I recently discovered this feature via vimcasts.
According to the manual, you can use Ctrl+R to insert the contents of a register into the current position in the command line. The manual also claims that Ctrl+Y inserts the text highlighted with the mouse into the command line. Remember that in X11 and some other systems, you can also paste text into a program from the system clipboard using the middle mouse button or a menu command in your terminal emulator.
I think to avoid have your command line be huge you can use this to solve your issue
:%s/foo/\=#a/g
That replaces "foo" with whatever is in register a.
If you're trying to do a substitute with a long complicated search pattern, here's a good way of going about it:
Try out the search pattern using some test cases and refine it until you have the pattern you want. I find incsearch really helps, especially with complicated regular expressions.
You can then use :%s//new to replace all instances of the last searched for pattern.
If you've entered a pattern and want to copy it out of the search history, you can use q/ to bring up a command line window containing recent search patterns very similar to the q: one that contains recent command history.
On the other hand, if you're asking about how to copy and paste text into the substitute command:
I'd write the pattern out in insert mode and yank the search and replacement into two distinct registers using, say, "ay and "by and then use :%s/<C-R>a/<C-R>b/gc to do the substitute. There are lots of variations of the yank command, but this one should also work automatically when using a visual selection.
If you're copying in text from the clipboard, you can use <C-R>* to paste it's contents in insert mode.
I have the following mapping in my .vimrc
vnoremap <leader>r "ry:%s/^Rr/
So I visually select the thing I want to replace, and hit ,r, type the replacement and hit return. If I want to paste the replacement, I yank it before selecting the text to replace, and then use <C-r>" to paste it as the replacement before hitting return.
Note: to insert ^R in your .vimrc, you actually type <C-v><C-r>.

Resources