15

I want to wrap some code :

myObj.text;

with a function call where the code is passed as an argument.

console.log(myObj.text);

I've thought about using surround.vim to do that but didn't manage to do it.

Any idea if it's possible ? I

Florian F
  • 8,822
  • 4
  • 37
  • 50
  • I made a plugin based on tpope's vim-surround that includes this: but more generally [vim-surround-funk](https://github.com/Matt-A-Bennett/vim-surround-funk) also allows you to delete, change and yank a surrounding function call, and paste it around any text object (and there's a text object for function calls, so you can paste it around them too!) – mattb Feb 01 '22 at 13:16

3 Answers3

19

With Surround in normal mode:

ysiwfconsole.log<CR>

With Surround in visual mode:

Sfconsole.log<CR>

Without Surround in normal mode:

ciwconsole.log(<C-r>")<Esc>

Without Surround in visual mode:

cconsole.log(<C-r>")<Esc>

But that's not very scalable. A mapping would certainly be more useful since you will almost certainly need to do it often:

xnoremap <key> cconsole.log(<C-r>")<Esc>
nnoremap <key> ciwconsole.log(<C-r>")<Esc>

which brings us back to Surround, which already does that—and more—very elegantly.

romainl
  • 186,200
  • 21
  • 280
  • 313
  • Thanks. I didn't know about the "f" char to input a function. How did you find out ? I haven't seen it in the help doc. – Florian F Jul 28 '17 at 17:25
  • 1
    I… don't remember. Either I learned it from someone else or I found about it by reading the source. – romainl Jul 28 '17 at 19:04
  • Is it possible to delete a surrounding function, similar to `dsb` `ds'` etc.? –  Dec 04 '20 at 00:41
  • @ArturTagisow there is no built-in function text object. If you manage to come up with a reasonably generic one then you will need to turn it into a pseudo-text object to be used as operator-pending motion, which is beyond the scope of this question/answer/comment thread. – romainl Dec 04 '20 at 15:49
6

I know and use two different ways to accomplish this:


Variant 1:

  1. Select the text you want to wrap in visual mode (hit v followed by whatever movements are appropriate).

  2. Replace that text by hitting c, then type your function call console.log(). (The old text is not gone, it's just moved into a register, from where it will be promptly retrieved in step 3.) Hit <esc> while you are behind the closing parenthese, that should leave you on the ) character.

  3. Paste the replaced text into the parentheses by hitting P (this inserts before the character you are currently on, so right between the ( and the )).

The entire sequence is v<movement>c<functionName>()<esc>P.


Variant 2:

Alternatively to leaving insert mode and pasting from normal mode, you can just as well paste directly from insertion mode by hitting <ctrl>R followed by ".

The entire sequence is v<movement>c<functionName>(<ctrl>R")<esc>.

cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106
1

You can use substitution instruction combined with visual mode

To change bar to foo(bar):

  1. press v and select text you want (plus one more character) to surround with function call (^v$ will select whole text on current line including the newline character at the end)

  2. type :s/\%V.*\%V/foo\(&\)/<CR>

Explanation:

  • s/a/b/g means 'substitute first match of a with b on current line'
  • \%V.*\%V matches visual selection without last character
  • & means 'matched text' (bar in this case)
  • foo\(&\) gives 'matched text surrounded with foo(...) '
  • <CR> means 'press enter'

Notes

  • For this to work you have to visually select also next character after bar (^v$ selects also the newline character at the end, so it's fine)
  • might be some problems with multiline selections, haven't checked it yet
  • when I press : in visual mode, it puts '<,'> in command line, but that doesn't interfere with rest of the command (it even prevents substitution, when selected text appears also somewhere earlier on current line) - :'<,'>s/... still works