10

Is there any way to jump to a buffer by entering buffer number right from :ls?

I mean, why this command expect me to Press ENTER or type command to continue, if pressing for example 2, wouldn't do anything?

Obviously I won't any plugin to be installed, at least one little script in .vimrc.

Thanks.

peterh
  • 1,147
  • 3
  • 16
  • 35
kAldown
  • 213
  • 2
  • 6

2 Answers2

14

Without changing anything the quickest way from that prompt is probably to press :b + number + Enter. But as a bit of a shortcut here's what I (and a lot of other people) use that gets me there from Normal mode:

:nnoremap <leader>ls :ls<cr>:b

You can replace <leader>ls with any unused Normal mode key combo. After pressing the keys you'll see the buffer list and you can enter the number + Enter without dealing with that Press ENTER... prompt.

Update: OP would like to override :ls altogether. That can be done with

:cnoremap ls ls<cr>:b

but this is not recommended since the mapping will happen anywhere "ls" is typed in a command or search term! (Thanks to Peter Rincker for the warning.) While you can overcome this by typing Ctrl+V before typing "ls" anywhere (e.g. to search for "hills" you'd have to do /hil^Vls) that's hardly convenient. Better to choose a key-combo that is unlikely to occur in commands or search terms. In Vim help they have an example with "_ls" so :cnoremap _ls ....

Update 2: I've since removed the <space> from my own mapping and edited the mappings above to reflect this. It's not necessary and, more importantly, I occasionally decide I want to unload a buffer from this point using :bd (aka :bdelete). The <space> meant having to type Backspace before d and the buffer number.

Also, there supposedly was going to be an update five months ago based on a suggestion in the comments from @Rich but that seems to have fallen through the cracks 'til now...

He offers a more robust handling of a command-line override of ls. His version behaves slightly differently from the :cnoremap mapping above: the latter shows the buffer list after typing ls while the other waits until a subsequent press of Enter. It's trivial to adapt his solution to match the above. Which one to choose is simply a matter of taste. Both have the benefit of avoiding any Ctrl-V nonsense and only activating upon typing ls/ls<CR> right after the command-line's opening : versus activating inappropriately upon typing them somewhere else.

Here's the improved mapping to replace the one above. Simply add <CR> after the first ls to get the other flavor.

cnoremap <expr> ls (getcmdtype() == ':' && getcmdpos() == 1) ? "ls\<CR>:b" : "ls"

I recommend trying both and going with whatever suits you best but make sure you :cunmap one before trying the other.

Or you can blow all of this off and just use <leader>ls from Normal mode like most people prefer to do. :)

B Layer
  • 19,834
  • 2
  • 30
  • 57
  • Good solution thought. But is it possible to wrap native :ls to :ls<cr>:b<space> (from your example). I mean about to overwrite rather than append new function. Thanks – kAldown Dec 14 '17 at 12:09
  • Sure...see my updated answer. – B Layer Dec 14 '17 at 12:14
  • Be careful with cmap's as they can expand in other command-line "modes" like search, /. – Peter Rincker Dec 14 '17 at 15:41
  • @PeterRincker you were right, now I can not search for :find utils, because it contains ls :D – kAldown Dec 14 '17 at 15:50
  • 1
    Vim help suggests typing Ctrl-V before you type any of the c-mapped chars so :find uti^Vls. Still a pain but I don't yet see any better approach. Perhaps you can map instead :lsx or :lsq and get used to using that instead of :ls. ("lsx" and "lsq" are unlikely to appear in real-life commands or searches.) – B Layer Dec 14 '17 at 16:56
  • Updated my answer with @PeterRincker 's warning. – B Layer Dec 14 '17 at 17:05
  • @BLayer Couple of thoughts: 1. To replace the :ls command, you wouldn't map ls, you'd map ls<CR> 2. That Ctrl-V advice does indeed seem unhelpful, especially as Vim is perfectly capable of checking whether you're typing :ls or :find utils Thus: cnoremap <expr> ls<CR> (getcmdtype() == ':' && getcmdpos() == 1) ? "ls\<CR>:b" : "ls\<CR>" – Rich Jan 13 '20 at 15:32
  • @Rich I agree, generally speaking, with your first point though I'm not sure about stating "you wouldn't do X, you'd do Y" because X works just fine. In fact, I deliberately chose that because for a double-command like this the alternative means having to hit Enter twice which is, to put it gently, crapola. IMO. I chose something that matches the "rhythm" of the nmap version. To your second point, maybe you should submit a patch to vim for the help docs with something along those lines. What they have now is, I think we'd agree, crapola. ;) – B Layer Jan 16 '20 at 00:36
  • @BLayer First off, I want to apologise. I should have written my comment more carefully, because it's rude, and I didn't mean it to be. Sorry. You're absolutely correct that your solution works fine, and now that you've explained that it was a deliberate choice to omit the <CR> I agree it's arguably better. From a UI consistency perspective, I think possibly it then makes more sense to map :b instead: what the user is actually doing is changing buffer (and we show them the list mid-command to make it easier). That's obvs. debatable, though, and either way it's not what the OP asked for! :) – Rich Jan 16 '20 at 09:47
  • RE: My second point, sounds like we're in agreement that this isn't the best part of the Vim docs :). (I'd take a guess that it's because the <C-V> suggestion predates getcmdpos().) Even so, I think it's worth mentioning in your answer that there's a better method. If you agree in principle but just don't want to spend the time to make the edit, I'd be happy to write one up (which you could obviously tweak/revert if you don't like it). – Rich Jan 16 '20 at 09:51
  • @Rich No apology necessary. I didn't interpret it as being rude. I just wanted to ensure it didn't lead anyone to think there was a right way and wrong way with this example. As for the second part, I was thinking of updating my answer with some of that but, as you surmised, I'm tight on time. Feel free to add an update to my answer. Cheers. – B Layer Jan 16 '20 at 19:03
2

You can get a workflow that's close to what you want without configuring vim at all.

You can jump to the nth buffer using <C-^> (ctrl + 6).

If you type a digit while viewing the output of ls, then that digit is stored and can be passed to the next command.

In order to produce the fake vim screenshots, I increased the font size so I can only see a few lines, and set the following listchars.

execute("set listchars=eol:\xc2\xac,tab:>\\ ,trail:\xe2\x81\x9b,extends:>,precedes:<,space:\\ ") 

So, if you do

$ mkdir -p /tmp/vim-example
$ cd /tmp/vim-example
$ vim ./a ./b

Then your screen will look like this:

¬                                 
~                                 
~                                 
~                                 
~                                 
~                                 
./a              0,0-1         All
"./a" [New File] 

You can look at the files by pressing :ls<cr>.

:ls                               
  1 %a   "./a"                    
      line 1                      
  2      "./b"                    
      line 0                      
Press ENTER or type command to con
tinue  

From there, if you type 2 and then <C-^> you will be taken to the next buffer.

¬                                 
~                                 
~                                 
~                                 
~                                 
~                                 
./b              0,0-1         All
"./b" [New File]  
Greg Nisbet
  • 1,839
  • 14
  • 27