In vim, there is a way to yank between two quotations by using yi'. And there is a way to yank between two square brackets by using yi].

I want to do this between two ##:


## Point #1 --> Copy this
some_code   --> Copy this (cursor here)
some_code2  --> Copy this
## Point #2

Also, I would like it to work even if there is no ## at the end of the file left

## Point 1

## Point 2

## Point 3   --> Copy this
some_code    --> Copy this
some_code2   --> Copy this (Cursor here)
some_code3   --> Copy this
             --> EOF here

3 Answers 3


I think your approach is correct, but some tweaks might be needed:

function! BlockCopy(pattern)
    call search('^' .. a:pattern, 'cbW')
    normal! 0V
    let l:bottom = search('^' .. a:pattern, 'nW')

    if l:bottom == 0
        normal! G
        call search('.', 'cb')
        execute l:bottom-1
onoremap <silent> m :<C-u>call BlockCopy('##')<CR>

This yanks the lines between markdown headers (including the headers themselves). It will also copy at most a single blank line at the end of the file, which is a more reasonable behavior.

  • Regarding the yanking between markdown headers, that could be desired but I personally want it to yank the markdown header. Especially because if I run dm I can delete the entire section with its header Aug 2, 2022 at 3:30
  • 1
    I think you misunderstood the comment about the last blank line. In your code, you're yanking to the end of the file. If you have several blank lines there before EOF, then all of them are also being yanked. normal! } prevents this.
    – r_31415
    Aug 2, 2022 at 3:49
  • 1
    Ahh, I didn't know about }. But that still work if there is a blank line before the end of the section? I'd assume the way to avoid this would be to go the end of the file with G and then going back up until you hit a line that has text. Aug 2, 2022 at 4:37
  • 1
    No, you're right. I forgot about blank lines before EOF. I updated my answer to keep headers and as you said, continue to the end and return to the first character. I think it works reasonably well now.
    – r_31415
    Aug 2, 2022 at 5:08
  • 1
    Note that in both answers :normal! G is the same as :$ and :execute 'normal!' (s:bottom-1)..'gg' is the same as :execute (s:bottom-1). Also note that you should prefer l:bottom to s:bottom; the former is local to the function, while the latter is scoped to the entire script (file) in which the function is defined.
    – D. Ben Knoble
    Aug 2, 2022 at 13:05

I got it, I used this tutorial to help understand how to do this in lua. The code to do it is given below, put it in a .lua file and source it from your init.lua to activate it.

function block_copy(pattern)
    local top = vim.fn.search('^' .. pattern, 'bW')

    vim.cmd('normal! 0V')

    local bottom = vim.fn.search('^' .. pattern, 'nW')

    if ( bottom == 0)
        vim.cmd('normal! G')
        vim.cmd('normal! ' .. bottom - 1 .. 'gg')

vim.api.nvim_set_keymap('o', 'm', [[:<C-u>lua block_copy('##')<CR>]], { noremap = true, silent = true})
vim.api.nvim_set_keymap('x', 'm', [[:<C-u>lua block_copy('##')<CR>]], { noremap = true, silent = true})

This can be used as a text-object (use vim's help to read up on it) by using m. And it takes in any pattern that you wish.

  • Are you sure this code is working as intended? It looks to me that it will yank the header, which is not what you specified in your question. It also jumps to the previous section when the cursor is placed in one of the headers.
    – r_31415
    Aug 2, 2022 at 2:03
  • @r_31415 Regarding your points. I do want it to yank the header, that way when I paste it into ipython I can see what section was pasted as a double confirmation. The jumping goes back to the first instance of ## that it finds when searching backwards; that is undesired. Aug 2, 2022 at 3:27
  • 2
    That's okay, but then your examples show the opposite ("some_code --> Copy this") and also take a look at that buggy behavior when your cursor is put in headers.
    – r_31415
    Aug 2, 2022 at 3:46
  • Yes indeed, my example code wasn't illustrated correctly. Aug 2, 2022 at 4:38
  • No problem. I updated my answer according to your actual requirements.
    – r_31415
    Aug 2, 2022 at 5:09

The targets plugin gives you this (and other) functionality.

You can do yi#, or yi, or any of these:

, . ; : + - = ~ _ * # / | \ & $

Although this plugin doesn't, and as far as I know can't be coerced to, work for the case where there is no ## at the end of the file.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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