24

My cursor is in the middle of a paragraph when I decide suddenly I need to copy that paragraph:

start

So I type vip to select the paragraph visually:

selected

Now I hit cmd+C to copy to clipboard (this may vary on your system, but shouldn't be relevant to my post's central question), which leaves my cursor at the beginning of the paragraph:

final

rather than the desired position, which is where it was when I started.

Note the same problem occurs when yanking the selection non-visually with yip.

I would like the default behavior to be "return to original cursor position" after doing selection/copy actions like this. Is there a configuration that makes this possible?

2
  • 11
    Yeah, I find this annoying too. I just tend to use marks for that purpose: mm "+yap `m (Note that "+y yanks to your system clipboard) Mar 3, 2016 at 4:06
  • 3
    I find it way useful to have the cursor placed either at the start, or at the end of the yanked zone. After all, what can I now do, with yanked text, and cursor inside it? It doesn't make much sense to do a put/paste now. But, if I want to do that later, it means I could also yank later ... maybe what you need now is just a mark.
    – VanLaser
    Mar 3, 2016 at 7:52

6 Answers 6

18

A possible solution is to use jumps:

Before yanking or visually selecting you can set a new jump which you'll be able to access after your cursor has moved. To do so use m`.

Then after your cursor has moved because of the yanking use ctrlo to jump back in the jump list. Also you can see the list of the available jumps with :jumps and navigate this list with ctrlo and ctrli

To sum up your workflow would be:

  • m`
  • yip
  • ctrlo

As using m` sets a mark, you can jump to it with `` instead of ctrlo.

You can read :h mark-motions and :h :jumps for more information.

4
  • I like this. Is there a way to make single quote behave like backtick in general, when jumping? single quote is easier to type, and usually i want to jump to the correct column position as well as the right line...
    – Jonah
    Mar 3, 2016 at 23:28
  • 1
    @Jonah, I map <leader>' to be `, which works quite well for me. (I use <space> as my leader.)
    – Numeri
    Mar 4, 2016 at 1:28
  • @Jonah: As Numeri said a mapping can be a good solution, otherwise if you want to get rid of backtick you can have a look at :h 'langmap'. I'm not saying it's the ideal solution but maybe it could be interesting for you.
    – statox
    Mar 4, 2016 at 8:35
  • @Johah, I actually swap the single quote and back tick using noremap ' ` noremap ` ' ... This is in my vimrc and works great Nov 22, 2016 at 22:30
13

You can avoid moving the cursor with:

:'{,'}y

See :help range, :help mark-motions, and :help :y.

3
  • 2
    Nice to know about, but is that what you actually do? It seems typing the 8 keystrakes, with two brackets, makes this harder than the mark solutions
    – Jonah
    Mar 3, 2016 at 23:24
  • 1
    That's what I would do if I was in your position. But I have no issue with the behavior you describe so I don't actually do that.
    – romainl
    Mar 4, 2016 at 7:54
  • 6
    @Jonah You still have the option to create a mapping. Something like :nmap <key> :'{,'}y<CR> should do the job.
    – statox
    Mar 4, 2016 at 8:31
12

My cursor is in the middle of a paragraph

If you've just edited it, the simplest solution is to type g ; which will position your cursor on the last edit position.

And if you haven't edited the paragraph, you could do a simple replace operation with the same character you are on (e.g. you're on h, you type rh) to trigger an edit "event" without actually editing anything.

3
  • 2
    +1: I always used '., but it can be very useful to navigate between the last changes with g; and g,.
    – mMontu
    Mar 3, 2016 at 16:26
  • 2
    Is there a version of g; which takes you to the correct column position as well?
    – Jonah
    Mar 3, 2016 at 23:19
  • @Jonah that's the behaviour by default. Isn't it working for you? It takes me always to the correct column and line position.
    – Al.G.
    Mar 4, 2016 at 8:20
5

The vim-easyclip plugin has a setting for this:

g:EasyClipPreserveCursorPositionAfterYank - Default 0 (ie. disabled). Vim's default behaviour is to position the cursor at the beginning of the yanked text, which is consistent with other motions. However if you prefer the cursor position to remain unchanged when performing yanks, enable this option.

It's a bit much for me to install an entire plugin just for this small feature, so I prefer using marks as per my comment.

2

vim solution :

source

You can just copy the paragraph to the clipboard with "+yip

Instead of selecting the paragraph and copying it just set an auto command with the TextYankPost event. In vim, I think you will need a plugin and in neovim, you can see an example below. Basically, the TextYankPost event will highlight your copy for some milliseconds.

If you simply copy you can use this function:

augroup yank_restore_cursor
    autocmd!
    autocmd VimEnter,CursorMoved *
        \ let s:cursor = getpos('.')
    autocmd TextYankPost *
        \ if v:event.operator ==? 'y' |
            \ call setpos('.', s:cursor) |
        \ endif
augroup END

Neovim solution:

local augroups = {}

augroups.yankpost = {

    save_cursor_position = {
        event = { "VimEnter", "CursorMoved" },
        pattern = "*",
        callback = function()
            cursor_pos = vim.fn.getpos('.')
        end,
    },

    highlight_yank = {
        event = "TextYankPost",
        pattern = "*",
        callback = function ()
            vim.highlight.on_yank{higroup="IncSearch", timeout=400, on_visual=true}
        end,
    },

    yank_restore_cursor = {
        event = "TextYankPost",
        pattern = "*",
        callback = function()
            local cursor = vim.fn.getpos('.')
            if vim.v.event.operator == 'y' then
                vim.fn.setpos('.', cursor_pos)
            end
        end,
    },

}

for group, commands in pairs(augroups) do
    local augroup = vim.api.nvim_create_augroup("AU_"..group, {clear = true})

    for _, opts in pairs(commands) do
        local event = opts.event
        opts.event = nil
        opts.group = augroup
        vim.api.nvim_create_autocmd(event, opts)
    end
end

NOTE: In both cases, it will only work in normal mode, although being possible to enhance it with some code.

The idea for the neovim solution and the vim solution comes from this answer on reddit.

1
0

Extending Al.G.'s answer, we can go to required location without editing. Solution is gi. We will reached to the same position where we was in last insert mode before.

  • You are in the middle of the paragraph.
  • switch to insert mode.
  • switch to normal mode.
  • press vip.
  • press gi.
  • switch to normal mode. (gi will left us to insert mode)

If we want to go to start or end of highlighted text.

 :help v_o 

When you yank the highlighted text, you will also return to normal mode and you may or may not retain the original cursor position.

  1. If you start highlighting from higher to lower cursor position(from lower line-column number to higher line-column number), you will retain original cursor position on pressing y
  2. Cursor will remain to current position if highlight start from lower to higher cursor position.

Returning to original location after yanking:
gv to get previous highlight.

Now you can switch between original and current location in visual mode with key
o or O.

Line and column number of status line will help to know exact cursor position.
Documentation:

:help visual-change
3
  • 1
    This doesn't work for vip when the cursor starts in the middle of a paragraph.
    – Antony
    Aug 31, 2016 at 10:03
  • Oh ya I didn't notice it, for now I will edit my answer rather than deleting it.
    – vusan
    Aug 31, 2016 at 10:57
  • @Antony Now it also works for vip check my edit.
    – vusan
    Sep 5, 2016 at 10:56

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.