Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace visual selection with command output

Tags:

vim

I would like to replace parts of one line with the result of the selection being piped into a command.

For example:

echo "hello $(echo "world" | base64)" | vim -

This will open a buffer with hello d29ybGQK in it. Now press wvw to visually select d29ybGQK.

Then I attempted :!base64 -d and I expected the buffer to contain hello world, which did not happen. Indeed, the whole line was piped into the command, and the whole line was replaced.

Is it possible to replace only the visual selection, and have only that selection piped into the command?

I also attempted c<c-r>=system('base64 -d') but that did not send the visual selection to the command's stdin.

like image 788
Benoit Duffez Avatar asked Sep 03 '26 04:09

Benoit Duffez


1 Answers

Filtering with ! is always line-wise. Your solution with c and the expression register is an excellent way to solve this. You only forgot to pass the input to system(), which is its second optional argument.

Since you just changed the text selected, it went into the " register automatically. All you need to do is to grab it back and pass it to system with getreg():

c<C-R>=system('base64 -D', getreg('"'))

Note that base64 may echo a newline at the end. If you want to remove it, either wrap the whole thing in trim(), a new function in Vim 8, or use [:-2]:

c<C-R>=trim(system('base64 -D', getreg('"')))
c<C-R>=system('base64 -D', getreg('"'))[:-2]

This is a shorthand for [0:-2], meaning grab everything from character 0 to second-last in the resulting string.

Consider creating a visual map if you use it often:

vnoremap <leader>d c<C-R>=system('base64 -D', getreg('"'))[:-2]<CR>
like image 177
sidyll Avatar answered Sep 04 '26 17:09

sidyll