1

I have been using vim mode for atom for quite a while, recently I've been trying to switch to nvim, but I can't seem to find a way to replicate the operator modifiers behaviour, which I've come to rely on quite frequently.

So for example, in the following paragraph:

hello this is me
writing to say hello
to everyone, so hello

Lets say that I wanted to change every occurrence of the word hello to the word hi, I could do that by navigating my cursor over any of the occurrences of hello and typing:

coip

I can't seem to find a convenient way to replace this behaviour, I'm open to any plugin suggestions as well, but a modifier like "o" seems pretty useful (or perhaps I'm missing a better way to do things).

Thanks in advanced.

  • I'm not sure the question is an exact duplicate but I think the answer I wrote there might answer your question. Here I would simply use :%s/hello/hi/g or a :%s/hello/hi/gc if you need to select which occurrences you want to change, but the closest of what you want is to use the dot command (explained in my other answer) – statox Oct 25 at 10:24
  • I'm interested. What's the behavior when current character is not a word character? e.g. cursor on ; of void foo();. – dedowsdi Oct 26 at 8:17
  • it finds every occurrence of ; and changes it as well from what I can see – user2662833 Nov 1 at 2:01
2

That is indeed a novel and potentially time-saving feature!

The way to do this in plain Vim would be using :substitute for a range; the pattern can be easily set via * when the cursor is on top of it:

*vip:s//hi/g<CR>

A mapping for the :s///g part that puts the cursor right into the replacement part can save many keystrokes here.

In order to support arbitrary text objects (ip covers entire lines, which plays well with the :{range}, but objects like is don't), the vis.vim plugin can help.

Plugin alternatives

I'm not aware of any plugin that implements this for Vim; however, my ChangeGlobally plugin offers something similar: Instead of having a fixed text (the cword with the operator modifier) applied over the specified {motion}, it applies the change or delete of a specified {motion} over a fixed range. I think the implementation could also support the other use case; I might add that to it ...

Update: I've added similar mappings to my plugin. Instead of the o operator modifier, I went with the plugin's existing mapping scheme. (Also, the plugin only handles changes and deletions, and cannot be applied to other actions like gU.)

These are the new mappings:

[N]["x]gc*{motion}      Delete the current whole \<word\> [into register x]
                        and start inserting. After exiting insert mode, that
                        text substitution is applied to all / the first [N]
                        occurrences inside {motion} text.

[N]["x]gx*{motion}      Delete the current whole \<word\> [into register x]
                        and apply the deletion to all / the first [N]
                        occurrences inside {motion} text.

[N]["x]gcg*{motion}     Delete the current word [into register x] and
                        start inserting. After exiting insert mode, that text
                        substitution is applied to all / the first [N]
                        occurrences inside {motion} text.

[N]["x]gxg*{motion}     Delete the current word [into register x] and
                        apply the deletion to all / the first [N] occurrences
                        inside {motion} text.

[N]["x]gc_ALT-8{motion} Delete the current whole \_sWORD\_s [into register x]
                        and ALT-8t inserting. After exiting insert mode, that
                        text substitution is applied to all / the first [N]
                        occurrences inside {motion} text.

[N]["x]gx_ALT-8{motion} Delete the current whole \_sWORD\_s [into register x]
                        and apply the deletion to all / the first [N]
                        occurrences inside {motion} text.

[N]["x]gcg_ALT-8{motion}Delete the current WORD [into register x] and
                        ALT-8t inserting. After exiting insert mode, that text
                        substitution is applied to all / the first [N]
                        occurrences inside {motion} text.

[N]["x]gxg_ALT-8{motion}Delete the current WORD [into register x] and
                        apply the deletion to all / the first [N] occurrences
                        inside {motion} text.

[N]["x]<Leader>gc{source-motion}{target-motion}
                        Delete {source-motion} text [into register x] and
                        start inserting. After exiting insert mode, that text
                        substitution is applied to all / the first [N]
                        occurrences inside {target-motion} text.
{Visual}[N]["x]<Leader>gc{motion}
                        Delete the selected text [into register x] and start
                        inserting. After exiting insert mode, that text
                        substitution is applied to all / the first [N]
                        occurrences inside {motion} text.

[N]["x]<Leader>gx{source-motion}{target-motion}
                        Delete the {source-motion} text [into register x] and
                        apply the deletion to all / the first [N] occurrences
                        inside {target-motion} text.
{Visual}[N]["x]<Leader>gx{motion}
                        Delete the selected text [into register x] and apply
                        the deletion to all / the first [N] occurrences inside
                        {motion} text.
  • Yes, I was already aware of substitutions, but I am really not a fan of them, they take way too many keystrokes :P but your change globally plugin looks pretty cool, I might try it out. Thanks for putting time into that, if you could support the "o" modifier as well, that would be awesome! – user2662833 Oct 25 at 9:03
  • Okay, I just tried it, just to document this. To achieve the same thing I can go viwgc but it does delete one character too far to the left (I might be doing it wrong). I can't figure out how to apply it to a paragraph either. – user2662833 Oct 25 at 9:53
  • That one-off might be a discrepancy of Neovim; it should work (with any value of 'selection') in Vim. Yes, it currently auto-applies the changes to the current line / whole buffer / [N] times. To support passed text objects as the scope of application, a different mapping needs to be implemented. – Ingo Karkat Oct 25 at 10:18
  • So, I just updated your plugin and tried gc* over a word, and I got an error E119: Not enough arguments for function: ChangeGlobally#OperatorExpression. Is that an invalid usage? The error occurred before I could specify a motion – user2662833 Nov 1 at 2:04
  • That should not happen. Do you use that in NeoVim or Vim? – Ingo Karkat Nov 1 at 8:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.