15

When I open vim with multiple files (vim f1 f2 ...), how can I make it open them in tabs directly, without using -p?

I'm looking to separate out shell behaviour from vim behaviour, removing vim-based aliases, etc. That's why I'd prefer not to use aliases, etc. (hence, no -p).

I'm pretty sure this one has been asked on a few SE sites (such as on SO). However, I'm in no position to judge what would be the best way to do this, so I'm also hoping for a note on why a suggested method is good.

For the particular SO post linked:

  • the accepted answer does tabpagemax=9999. Call it personal bias, but I see a limit being set to a large number and I think there's something wrong (the way I'd feel if I saw chmod 777).

    :au VimEnter * set tabpagemax=9999|sil tab ball|set tabpagemax&vim
    
  • the other answer leads to an extra empty tab being opened, while being far more concise.

    :autocmd VimEnter * argdo tabedit
    

I'm hoping for an answer which doesn't have an extra tab opened and doesn't set a limit to a large value (or explain why that's not a bad thing).

muru
  • 24,838
  • 8
  • 82
  • 143
  • @OrangeTux I posted in the spirit of Gilles' answer. But with the downvote I wonder what would Gilles say to a post linking to an existing post? – muru Feb 04 '15 at 15:20
  • @Carpetsmoker I didn't see your comment update. An empty tabpage is not a big problem when your sessions tend to end with :qa by force of habit. If that's the only advantage I'd go with the other one, since it does seem simpler. – muru Feb 04 '15 at 15:24
  • 3
    @muru WWGS? Do you have a reason to think the answers on [so] aren't satisfactory? If so, explain that in your question. In any case, summarize the SO answers in your question. If that leads to the question containing its own answer, don't post. – Gilles 'SO- stop being evil' Feb 04 '15 at 15:29
  • @Gilles Updated. I didn't post the actual commands, do you think I should? – muru Feb 04 '15 at 15:34
  • @muru Since none of the commands meet all of your requirements, it isn't necessary to post them. It might be useful, however, to stave off answers that say “just do X” only for you to have to reply “no, that doesn't meet requirement #3”. – Gilles 'SO- stop being evil' Feb 04 '15 at 15:44
  • Why do you need to use a tab page for every buffer? There are many ways to navigate through the open buffers in a single tab page. Vim's tab pages are intended to be used more like viewports than as a representation of a file. The latter is already implemented by Vim's buffers. – jamessan Feb 04 '15 at 17:02
  • @jamessan Why not? What do I gain from using buffers instead? With tabs, I can see a quick visual indication of which file I'm editing. I'm pretty sure that can be done with buffers. I have read this famous post, but if I were to make an analogy: I don't see why I should use Firefox's tab groups instead of having windows open in different workspaces. I have never really gotten used to navigating buffers, but if the reasoning is strong enough, I don't mind switching. – muru Feb 04 '15 at 17:14
  • Everything in Vim is built around buffers. Windows exist to view buffers. Tab pages exist to organize windows. Buffers can be displayed in any number of windows (and therefore tab pages). Ignoring the fact that the buffer is the core object is just limiting your potential experience with Vim. Using tab pages just for the visual cue of the buffer doesn't scale, because eventually the tab page title becomes too small. Maybe I should make an answer to go further. – jamessan Feb 04 '15 at 17:27
  • @muru I'd recommend checking out one of the buffer plugins that is mentioned in the "Stop stop stop" answer you linked to: they'll give you the visual indication you're looking for without trying to force Vim's tabs to work in a way they weren't designed. – Rich Feb 10 '15 at 10:17
  • When I saw the "this famous post" link, I was sure it was to this one: http://stackoverflow.com/a/26710166/5419599 But it wasn't. That (the one I just linked) was by far the most helpful post I have found anywhere for understanding the distinct purposes of buffers, tabs and windows. – Wildcard Dec 02 '15 at 02:51

3 Answers3

9

After some experimentation I've found this to be the best way; it should behave the same as vim -p:

augroup open-tabs
    au!
    au VimEnter * ++nested if !&diff | tab all | tabfirst | endif
augroup end

tab all opens all the entries in the argument list (:args) in a tab. The argument list is a list of files you passed to Vim on startup. And the tabfirst makes sure the first tab is focused rather than the last (this is optional).

We don't do any of this if &diff is set; if it is, we're using vimdiff or vim -d, where we want to have 2 windows, and not 2 tabs.

In this answer I've also written a bit about the argument list and tab all which may be of interest.

The ++nested part is required to run autocommands such as BufRead for the files we open.


Some notes about the other solutions:

  • tab ball opens a tab for every entry in the buffer list, not the argument list. The "problem" is that the buffer list may be saved in the viminfo file when quiting and is restored on startup if % is in 'viminfo' (not enabled by default). So if you just type vim it will open those files. Personally I wouldn't want that, though I can imagine some people finding it useful; so use what you prefer.

  • set tabpagemax=9999 is not required; the default of 10 should be fine. You can increase this in your vimrc if you want more, but 9999 is a silly number. If you use -p, you also get tabpagemax tabs so this should respect that. Remember that this will open (read) a buffer on startup, so it's rather slow.

  • autocmd VimEnter * argdo tabedit is just the same way of saying tab all. However, the initial buffer isn't cleared, so you're left with that extra tab (tab all replaces all tabs). To fix this, you need the workaround in Josh Petrie's answer.

Martin Tournoij
  • 62,054
  • 25
  • 192
  • 271
  • Thanks a lot for this answer. It works great on vim >= 8.1, but not on vim 8.0 which I am stuck with on a legacy machine. Any idea as to why it does not work on vim 8.0 and how to get it to work? – gothicVI May 27 '22 at 14:54
  • 1
    What error do you get @gothicVI? And which Vim patchlevel are you using (i.e. the third digit after 8.0)? – Martin Tournoij May 27 '22 at 17:37
  • @MartinTournoij thanks for the reply. No third digit but:

    $ vim --version

    VIM - Vi IMproved 8.0 (2016 Sep 12)

    Included patches: 1-1568

    The error when opening vim or one or more files is:

    Error detected while processing VimEnter Auto commands for "*":

    E492: Not an editor command: ++nested if !&diff | tab all | tabfirst | endif

    – gothicVI May 28 '22 at 19:19
  • 1
    @gothicVI ++nested was added in Vim 8.1.1113; but I believe just nested without the ++ should work in older versions, but I didn't try it to confirm. – Martin Tournoij May 29 '22 at 22:05
  • Amazing that seems to work. Could you briefly explain why, or what (++)nested even does, respectively in this case? – gothicVI May 31 '22 at 07:54
2

I think adding something like this to your .vimrc may solve your problems (note, however, that I don't actually use this and have only done minimal testing, it may do strange things in some cases):

function! OpenArgumentsInTabs()
  ardo tabedit
  if tabpagenr("$") > 1
    tabclose
  endif
endfunction

autocmd VimEnter * call OpenArgumentsInTabs()

As you noted, argdo tabedit will leave you an empty extra tab. So you can simply close that tab automatically. However, you can't just invoke tabclose unchecked, or vim will give you an error when you launch it without arguments or a single file (you "can't close the last tab"). Instead, check to see if the total number of tabs is greater than one (that's what $ causes tabpagenr to return) and only then do you need to close the last tab.


That said, I feel like it's worth pointing out that vim's tabs aren't quite like other editors' tabs, and that's something to keep in mind when considering how to use tabs in your workflow (you seem to be aware of this, but I want to make the point for the benefit of future readers who might not so they can make their own decisions).

0

I've come up with a simpler solution that meets my own needs.

It doesn't meet the OP's requirement of not using -p (unless hiding it behind a script is good enough).

Note that vim -p single_file seems to behave the same as vim single_file, so always using the -p option doesn't appear to be a problem.

I habitually invoke vim by typing vi or view. I find the behavior of the -p option preferable to the default behavior, but I still want to be able to fall back to the default, or to use -o or -O, if I want to.

I've created wrapper scripts called vi and view and added them to my $HOME/bin directory, which precedes /usr/bin and /bin in my $PATH.

vi:

#!/bin/sh
exec vim -p "$@"

view:

#!/bin/sh
exec vim -R -p "$@"

An alias or shell function would do the same thing.

If I want to fall back to the default behavior, I can type vim or vim -R rather than vi or view.

(I still have $EDITOR set to vim. I might consider changing it to vi if it becomes an issue, but most programs that use $EDITOR don't invoke the editor with multiple file names.)

Keith Thompson
  • 207
  • 1
  • 6
  • Could have just used an alias. – muru Aug 28 '21 at 00:27
  • @muru True, but a script lets me add refinements later. For example, I might decide I want it not to use -p if it sees -o or -O. (For now I just do that by typing vim rather than vi.) – Keith Thompson Aug 28 '21 at 01:29
  • 2
    Don't those options anyway override each other? So a vim -p alias with -O filename would use the -O behaviour – muru Aug 28 '21 at 01:42
  • @muru I hadn't thought about that. It appears they do, but as far as I can tell it's not documented. – Keith Thompson Aug 28 '21 at 01:51
  • If you use zsh then =word expands to the full path of word from $PATH; e.g. print vim will print /usr/bin/vim. This can be useful to override aliases if you need it: =vim file will skip any aliases, as if you typed /usr/bin/vim file. I don't think bash has anything similar. – Martin Tournoij May 29 '22 at 22:12