6

I have a bad habit of deleting some text a, heading off to another section of the document to paste it, and finding something else along the way that I need to delete. When I get to my final destination, where I want to paste the originally deleted text a, it's no longer in the default register.

I know that this is easy to fix by thinking ahead and deleting the text into a named, rather than the default, register. However, in the absence of that foresight, what I do instead is hope I haven't deleted too much text in the meantime, and look through the numbered registers until I find a.

The problem is that a is usually not just a single character, but rather a large block of text, and I might only remember a passage from the middle of that block when I am searching the registers. Since :reg only shows a one-line preview of each register, I can't necessarily find a by visual inspection.

Is there a command that I can issue to match a given regex against, not a specific register, but all registers, and that will tell me, say, "your regex matches in "3 and "7"?

3 Answers 3

5

Here's a script you can put in ~/.vim/plugin/registers.vim for a command :Registers that does :registers on all registers matching the commands argument (pattern).

if exists('g:registers')
  finish
endif
let g:registers = 1

const s:registers = [
      \ '"',
      \ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
      \ '_',
      \ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
      \ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
      \ ':', '.', '%',
      \ '#',
      \ '=',
      \ '*', '+', '~',
      \ '/',
      \ ]

function FindMatchingRegister(text) abort
  return s:registers->copy()->filter({_, v -> getreg(v) =~ a:text })
endfunction

command -nargs=1 Registers execute 'registers' FindMatchingRegister(<q-args>)->join()
14
  • This is pretty useful; I think I'll stick it in my vimrc! It gives an error if nothing matches though; need a check for that. This is what I ended up with for now, but it's Vim9Script. I also changed nargs to * so :Registers will work as :registers. Jun 8 at 19:04
  • Also wonder if there isn't a better way to list all register names, but can't find any 🤔 Jun 8 at 19:06
  • 1
    Looks like it's because I have vim9script in my vimrc; the command seems to behave different in that context. It works if I save it to a.vim and then :source a.vim. Jun 9 at 13:54
  • 1
    @LSpice with the current code, if there is no match (i.e., the result of FindMatchingRegisters is empty), then the command does the equivalent of :registers. One way to fix this might be to use command -nargs=1 Registers execute 'registers' (FindMatchingRegister(<q-args>) ?? ['_'])->join() but it's a bit hacky (:registers _ is basically always blank).
    – D. Ben Knoble
    Jun 10 at 18:21
  • 1
    @LSpice woops! I didn't think about your /s. They aren't needed, actually: anything after :Registers will be used as a single argument to the function, which is then used in the pattern spot. In commands :substitute or :global, the pattern is the bit between the delimiters (the delimiters themselves are not considered part of the pattern). So simply :Registers def should do it. (If you're used to, say, JS or Perl, where // look like they create a regexp… they stole the idea from ed/ex/vi/vim. But they got it kinda wrong :P )
    – D. Ben Knoble
    Jun 10 at 18:24
6

"Unnamed" register is not a real one. It's just a pointer. When you delete the text that has more than one line it goes into register 1. The previous text of the register 1 goes into the register 2, and so on upto 9.

Hence your text must be in one of registers 1-9. You can start trying by pasting from the register 1 with "1p. If no luck then press u. to undo and to paste from the register 2, and so on.

Every time you press "dot" the register number will increase by one. This is a special feature documented at :h redo-register.

3
  • Thanks for the tip about <kbd>u</kbd><kbd>.</kbd>; I didn't know that! But I did understand about the auto-promotion of numbered registers, and was hoping for something that would save me doing this potentially many times by simply telling me automatically which numbered registers had the desired content. @ChristianBrabandt's answer is almost exactly what I was looking for, except that it only peers into the first line of each register.
    – LSpice
    Jun 8 at 16:50
  • @LSpice You can implement something like that with a bit of scripting. Or find some plugin that allows to browse through registers content before pasting(smth. about "peek register" in title).
    – Matt
    Jun 8 at 17:13
  • 1
    I believe this is the best suggestion and this tip is very convenient.
    – r_31415
    Jun 8 at 21:59
4

In general, I would just use the :reg command to check what is in the various registers.This usually helps already.

But using the :filter command, you can also apply a regex to search inside the register content and only show those registers that match your regex:

:filter /regex/ reg

So this will filter the output of the :register command and only show those, that match the given regular expression regex.

Note, that it will only try to match on the first line in the register. This matters, because register can contain many lines.

4
  • 1
    That's almost exactly what I want, except the "only … the first line in the register" part. I guess there's no way to force it to search the full contents of each register? (This is the same reason that I don't just use :reg—I'm looking for content that may be buried many lines deep in the register.)
    – LSpice
    Jun 8 at 16:48
  • 1
    nope, no way to make it search everything I believe Jun 8 at 16:55
  • Thanks! I'll wait a bit in case someone else knows some secret arcana to force it to do so; but, if not, then this is as close as possible to what I want, so I will accept it.
    – LSpice
    Jun 8 at 16:56
  • Thank you very much again for this answer. It is extremely close to what I want, and built in, which is a plus; but @D.BenKnoble's answer does exactly what I want with some scripting, so I wound up accepting it. We all know the dilemma—if I could have accepted two, I would have accepted this one too!
    – LSpice
    Jun 10 at 18:27

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.