Full restore
If you want to restore layout with multiple termina buffers, you must restore other windows and buffers too, so it's in fact a full buffer layout restore, it's usage is not limited to terminal buffers. Three things must be done to achive that:
- Split windows according to saved layout. We can use result of
winlayout() to do this. - Load buffer in each window. We must record
bufnr in each window when we save winlayout(). - Resize each window. We can use
:h winrestcmd() to do this.
Two recursions are used to save and restore layout:
command SaveBufferLayout call s:save_buffer_layout() command RestoreBufferLayout call s:restore_buffer_layout() function s:save_buffer_layout() abort let s:buf_layout = winlayout() let s:resize_cmd = winrestcmd() call s:add_buf_to_layout(s:buf_layout) endfunction " add bufnr to leaf function s:add_buf_to_layout(layout) abort if a:layout[0] ==# 'leaf' call add(a:layout, winbufnr(a:layout[1])) else for child_layout in a:layout[1] call s:add_buf_to_layout(child_layout) endfor endif endfunction function s:restore_buffer_layout() abort if !has_key(s:, 'buf_layout') return endif " create clean window new wincmd o " recursively restore buffers call s:apply_layout(s:buf_layout) " resize exe s:resize_cmd endfunction function s:apply_layout(layout) abort if a:layout[0] ==# 'leaf' if bufexists(a:layout[2]) exe printf('b %d', a:layout[2]) endif else " split cols or rows, split n-1 times let split_method = a:layout[0] ==# 'col' ? 'rightbelow split' : 'rightbelow vsplit' let wins = [win_getid()] for child_layout in a:layout[1][1:] exe split_method let wins += [win_getid()] endfor " recursive into child windows for index in range(len(wins) ) call win_gotoid(wins[index]) call s:apply_layout(a:layout[1][index]) endfor endif endfunction
It's possible to make it work for multiple layouts, you can the newest script here.
Original manual workaround
It's trouble and buggy to toggle multiple terminal windows, you can step back, split by manual, then load the hided terminal buffer by mark or buffer number.
You can create global mark for terminal buffer by <c-w>:mark X or <c-w>:kX, hide it, and load it back with 'X, here is a map that let you create mark with <c-w>m{capital letter}:
tnoremap <expr> <c-w>m printf('<c-w>:mark %s<cr>', nr2char(getchar()))
Note that you can also combine the split and load together in a single command:
new +'X
You can also use :ls R or :ls F to list terminal buffer.
winlayout
:h winlayout()
The result is a nested List containing the layout of windows in a tabpage. ... For a leaf window, it returns: ['leaf', {winid}] For horizontally split windows, which form a column, it returns: ['col', [{nested list of windows}]] For vertically split windows, which form a row, it returns: ['row', [{nested list of windows}]]
leaf item contains :h winid , it's an uique id across tabs.
This is a horizontally splited col, it has 3 leafs:
┌─────┐ │ │ ├─────┤ │ │ ├─────┤ │ │ └─────┘
This is a vertically splited row, it has 3 leafs:
┌────┬────┬────┐ │ │ │ │ └────┴────┴────┘
They can be nested, this layout is a row, it's splited into two col, each col is splited into two leafs:
┌──────┬──────┐ │ 1 │ 3 │ ├──────│──────┤ │ 2 │ 4 │ └──────┴──────┘
this layout is a col, it's splited into two row, each row is splited into two leafs:
┌──────┬──────┐ │ 1 │ 2 │ ├─────────────┤ │ 3 │ 4 │ └──────┴──────┘
Note that :h winnr() for above two layouts are different.