17

When I need to work on different projects at the same time I have the folowing workflow:

  • I create one tab for each project.
  • In each tab I open the files that I want to edit, which makes several buffers.
  • Optionnaly if I need to see two (or more) files at the same time I create split windows so I have a tab containing different windows which shows one buffer.

To navigate between my buffers I don't really use :ls and :b [name or number of buffer] instead I created some convenient mappings allowing me to switch between the buffers with :bnext and :bprevious

This way to work is pretty good but something bothers me: the buffers are shared between the tabs.

If I open file1 and file2 in tab1 and file3 in tab2, if in tab1 I use several time :bnext I'll see file3 in this tab which I don't want to. The workflow I'd want to get is the folowing:

  • Start vim (I have a first tab with a buffer in it): $ vim foo
  • Add a buffer to this tab: :e bar
  • Open a new tab and switch to it: :tabnew
  • Open a new buffer in this tab: :e baz
  • If I stay in this buffer and do :bnext or :bprevious I'll stay on baz buffer (since it is the only one in this tab)
  • If I go in the previous tab :tabprevious and execute several time :bnext I'll switch only between foo and bar buffers but will not see baz

So here comes my question: Is it possible to bind a set of buffers to a tab and make vim disallow the access to some buffers from another tab than the one they're meant to be in?

Note: I'm aware that using :b [myBuffer] would be a way to keep a buffer in a tab but when I have 3 or 4 files to edit I feel like I'm really faster using my mappings than typing the buffer name (even if I can type only some characters to match the buffer name).

3
  • 1
    Here's an old discussion highlighting the pro's and con's of such an approach, and suggesting instead something that today could be translated as: multiple vim instances (one per project/buffer list) + tmux: vim.1045645.n5.nabble.com/…
    – VanLaser
    Jul 30, 2015 at 17:24
  • @VanLaser: Thanks for the link it's an interesting discussion! I actually include tmux and different vim instances when I'm on my personal machine. My question comes from the fact that I have to use windows for my professional work and I really don't like how the windows are handled: using alt+tab (or even worse the mouse) feels much less easy than switching tab within vim.
    – statox
    Jul 31, 2015 at 7:27
  • 1
    Maybe vim-ctrlspace can help - it advertises per tabpage buffer lists; I don't use it, though.
    – VanLaser
    Jul 31, 2015 at 10:33

7 Answers 7

9

Mhh, i did not find any plugin out there, but you could write it yourself. You need to learn vimscript for this. I just implemented the functionality that you can switch between buffers in a tab (no deletion yet). You can copy this into your vimrc:

if !exists("g:WindowBufManager") 
  let g:WindowBufManager= {}
endif

function! StoreBufTab()
  if !has_key(g:WindowBufManager, tabpagenr())
    let  g:WindowBufManager[tabpagenr()] = []
  endif

  " add the new buffer to our explorer
  if index(g:WindowBufManager[tabpagenr()], bufname("%")) == -1 && bufname("%") != ""
    call add (g:WindowBufManager[tabpagenr()],bufname("%"))
  endif
endfunction

function! WindowBufManagerNext() 
  " find the next index of the buffer
  let s = index(g:WindowBufManager[tabpagenr()], bufname("%"))
  if (s!= -1)
    let s = (s +1) % len(g:WindowBufManager[tabpagenr()])
    execute 'b ' . g:WindowBufManager[tabpagenr()][s]
  endif
endfunction

augroup WindowBufManagerGroup
  autocmd! BufEnter * call StoreBufTab()
augroup END

Close your vimrc and open it again. To find the next buffer just use

:call WindowBufManagerNext()

or define your own command or mapping. This will work as long as you do not close or delete a tab or buffer. It will also not work for multiple buffers. It would require some more work to add those features, but its definetly doable.

1
  • I didn't find a plugin neither and I was hoping for a built-in feature to do so but it seems that you're right I'll probably have to do it by myself. Thanks for your code I might use it has a base to develop a full plugin.
    – statox
    Jul 31, 2015 at 7:34
6

Buffers are global and there's nothing you can do about that except writing your own abstraction layer on top of tab pages, windows and buffers. philolo1's answer shows a reasonable approach to the problem but you'll quickly find the limits of such a "solution" and need to duplicate a lot of built-in features like :bufdo or the alternate file…

"Arguments" on the other hand, can be local to a window so they may be more useful in your workflow than "buffers" (in the strictest meaning of the word):

$ vim file1 file2
:tabnew
:argl file3 file4 file5
:n
:n
gt
:n
gt
:N
and so on…

Arguments are not as flexible as buffers but they may provide a more dependable basis for your workflow.

But working on each project in its own Vim instance is in my opinion the only practical solution.

1
  • I agree with the idea that using separate vim instances is better when I can use it in a terminal, as I said in another comment I have to use windows on my professional computer and switching between gvim instances is a pain in the butt with this OS. I'll take a look at the arguments I've never used it before and that might be a good workaround, thanks!
    – statox
    Jul 31, 2015 at 7:31
2

So, with some delay, I think I may have found a satisfactory (at least for me!) answer. You will need two of Shougo's plugins:

and a quick access map to use instead of :ls, to view (and select) only buffers from the current tab.

For example, something like:

nnoremap <leader>b :<C-u>Unite buffer_tab -no-split<CR>

unite - per tab buffers

You can now move through the current's tab buffer list (j, k), select one (CR), cancel (q), enter "input" (insert) mode to quickly filter the buffer selection by typing some letters, or even hit Tab to open the action list for the current selected item (e.g. to open the buffer above the current active one) - in short, you act in the generic "Unite" way.

(see also :h unite_default_key_mappings and Unite help in general).


And now for the final (yet optional) trick. With altercmd, you can create your very own, tab-wise enabled, ls command (based on the above Unite functionality):

:command! LS Unite buffer_tab -no-split
:AlterCommand ls LS

... and everytime you hit :ls, Vim will actually run your command instead.

Note that you also won't need :bn or :bp, since tab's buffers viewing and selection are now the same command.

1
  • I'll try this solution too. For the moment I'm giving a try to ctrl-space mentionned by VanLaser in the comment, which is pretty good. I'll see which solution is the most convenient. Also +1 for the altercmd plugin which is pretty cool!
    – statox
    Aug 10, 2015 at 8:09
2

I can't comment because my account is new so sorry about that, but ++++1 for ctrl-space.

I was sold by the time I made it halfway through the help. Ctrlspace has a structure like this:

workspaces --> contain tabs --> contain buffers

So, you can save a workspace for each project that you are working on and then immediately load it whenever you want. This means that any time you close vim you can save all of your buffer and tab splits.

You can also name your tabs. If that isn't enough, you can also very easily change working directories and create bookmarks for directories that you use frequently.

It interfaces nicely with nerdtree if you use that (although honestly you probably won't even feel like you need it after a week with ctrlspace)


Consider this use case:

You have a project. It involves planting trees. There are fruit trees and money trees. Money trees contain dollars and cents while fruit trees contain apples and oranges.

In this example apples, oranges, dollars, and cents are all "buffers."

Ctrlspace lets you separate apples and oranges into one "tab" which you can label "fruit" -- this label will appear in the tag line at the top of your window. Likewise, dollars and cents go into a "money" tab.

The "trees" workspace saves this entire configuration and lets you access it immediately any time you open vim.


Now that I'm aware of it's existence, I really can not imagine doing object oriented development in vim without this plugin. Just in case, here is the link: https://github.com/szw/vim-ctrlspace

2

So finally decided to create my own plugin to solve my problem, it is available on github.

I used the idea of @philolo1 and tried to complete it, at the time I'm writting this answer it is still a work in progress.

EDIT I no longer maintain the plugin as my workflow as evolved and I realized binding buffers to a tab adds more problem than it solves.


The plugin binds buffers to tabs: When the user open a buffer, it is automatically "stored" in the tab and can't be accessed from another tab.

The installation should be "plugin manager friendly" (at least it works well with Vim-Plug and Vundle)

Some of the main features are:

  • Automatically handle the binding of buffers (the user can open them as he did before)
  • :NextBuf and :PrevBuf replace :bn and :bN to keep a consistent state of the tabs
  • :ListBuf allows to list the buffers similarly to :ls excepted that they are separated in tabs and a sign let the user see easily in which tab he currently is.
  • :ChangeBuf accept a buffer number or a buffer name to change of buffer and change of tab automatically
  • Closing a buffer is done with :CloseBuf
  • Closing a tab is done with :CloseTab

For other operations the user should be able to use the built-in features (like :tabopen, :tabnext, etc...)

For each commands some default mappings are provided and they can be easily disabled by adding let g:betterTabsVim_map_keys = 0 to your .vimrc.

I also tried to make an explicit help file (:h betterTabs.txt): it is not complete yet but users should find the minimum to use the plugin.

I still have a lot of testing to do to be sure that the plugin doesn't mess any native behavior.

Finally if anyone wants to help it is always possible de create issues on the github page or to create pull requests.

1

Check out this plugin. It seems to me it suits your needs perfectly. https://github.com/szw/vim-ctrlspace

1
  • Indeed VanLaser mentionned it in the comments and I didn't look at it close enough at first but it seems to be really good, I've been trying it for a few days now.
    – statox
    Aug 10, 2015 at 8:11
0

For me the win-tabs plugin works best https://github.com/zefei/vim-wintabs

3
  • 2
    Hey welcome on this site :) Your answer would benefit from a brief description of the plugin and the reasons why it works best for you.
    – statox
    Aug 12, 2021 at 15:38
  • On the plugin website there are some recomended mappings. When you apply them the win-tabs bind all open buffers into each window. If you do not use splits it is doing what you asked
    – PBlasiak
    Aug 13, 2021 at 17:52
  • You should use the edit button to add details to your questions. If you can show some example of these recommended mappings and also precise arguments of why this solution works best for you that makes your answer much more interesting to users with the same needs
    – statox
    Aug 16, 2021 at 19:08

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.