vim-patch:8.1.2020: it is not easy to change the window layout

Problem:    It is not easy to change the window layout.
Solution:   Add win_splitmove(). (Andy Massimino, closes vim/vim#4561)
d20dcb3d01
This commit is contained in:
Andy K. Massimino
2021-03-18 21:51:20 -04:00
parent 0f7b6b2efd
commit 1ef4340f22
4 changed files with 134 additions and 0 deletions

View File

@@ -2498,6 +2498,8 @@ win_gotoid({expr}) Number go to |window-ID| {expr}
win_id2tabwin({expr}) List get tab and window nr from |window-ID|
win_id2win({expr}) Number get window nr from |window-ID|
win_screenpos({nr}) List get screen position of window {nr}
win_splitmove({nr}, {target} [, {options}])
none move window {nr} to split of {target}
winbufnr({nr}) Number buffer number of window {nr}
wincol() Number window column of the cursor
winheight({nr}) Number height of window {nr}
@@ -9370,6 +9372,25 @@ win_screenpos({nr}) *win_screenpos()*
Return [0, 0] if the window cannot be found in the current
tabpage.
win_splitmove({nr}, {target} [, {options}]) *win_splitmove()*
Move the window {nr} to a new split of the window {target}.
This is similar to moving to {target}, creating a new window
using |:split| but having the same contents as window {nr}, and
then closing {nr}.
Both {nr} and {target} can be window numbers or |window-ID|s.
Returns zero for success, non-zero for failure.
{options} is a Dictionary with the following optional entries:
"vertical" When TRUE, the split is created vertically,
like with |:vsplit|.
"rightbelow" When TRUE, the split is made below or to the
right (if vertical). When FALSE, it is done
above or to the left (if vertical). When not
present, the values of 'splitbelow' and
'splitright' are used.
*winbufnr()*
winbufnr({nr}) The result is a Number, which is the number of the buffer
associated with window {nr}. {nr} can be the window number or

View File

@@ -392,6 +392,7 @@ return {
win_id2tabwin={args=1},
win_id2win={args=1},
win_screenpos={args=1},
win_splitmove={args={2, 3}},
winbufnr={args=1},
wincol={},
windowsversion={},

View File

@@ -3980,6 +3980,85 @@ static void f_win_screenpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
tv_list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
}
//
// Move the window wp into a new split of targetwin in a given direction
//
static void win_move_into_split(win_T *wp, win_T *targetwin,
int size, int flags)
{
int dir;
int height = wp->w_height;
win_T *oldwin = curwin;
if (wp == targetwin) {
return;
}
// Jump to the target window
if (curwin != targetwin) {
win_goto(targetwin);
}
// Remove the old window and frame from the tree of frames
(void)winframe_remove(wp, &dir, NULL);
win_remove(wp, NULL);
last_status(false); // may need to remove last status line
(void)win_comp_pos(); // recompute window positions
// Split a window on the desired side and put the old window there
(void)win_split_ins(size, flags, wp, dir);
// If splitting horizontally, try to preserve height
if (size == 0 && !(flags & WSP_VERT)) {
win_setheight_win(height, wp);
if (p_ea) {
win_equal(wp, true, 'v');
}
}
if (oldwin != curwin) {
win_goto(oldwin);
}
}
// "win_splitmove()" function
static void f_win_splitmove(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
win_T *wp;
win_T *targetwin;
int flags = 0, size = 0;
wp = find_win_by_nr_or_id(&argvars[0]);
targetwin = find_win_by_nr_or_id(&argvars[1]);
if (wp == NULL || targetwin == NULL || wp == targetwin) {
EMSG(_(e_invalwindow));
rettv->vval.v_number = -1;
return;
}
if (argvars[2].v_type != VAR_UNKNOWN) {
dict_T *d;
dictitem_T *di;
if (argvars[2].v_type != VAR_DICT || argvars[2].vval.v_dict == NULL) {
EMSG(_(e_invarg));
return;
}
d = argvars[2].vval.v_dict;
if (tv_dict_get_number(d, "vertical")) {
flags |= WSP_VERT;
}
if ((di = tv_dict_find(d, "rightbelow", -1)) != NULL) {
flags |= tv_get_number(&di->di_tv) ? WSP_BELOW : WSP_ABOVE;
}
size = tv_dict_get_number(d, "size");
}
win_move_into_split(wp, targetwin, size, flags);
}
// "getwinpos({timeout})" function
static void f_getwinpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{

View File

@@ -808,6 +808,39 @@ func Test_winnr()
only | tabonly
endfunc
func Test_win_splitmove()
edit a
leftabove split b
leftabove vsplit c
leftabove split d
call assert_equal(0, win_splitmove(winnr(), winnr('l')))
call assert_equal(bufname(winbufnr(1)), 'c')
call assert_equal(bufname(winbufnr(2)), 'd')
call assert_equal(bufname(winbufnr(3)), 'b')
call assert_equal(bufname(winbufnr(4)), 'a')
call assert_equal(0, win_splitmove(winnr(), winnr('j'), {'vertical': 1}))
call assert_equal(0, win_splitmove(winnr(), winnr('j'), {'vertical': 1}))
call assert_equal(bufname(winbufnr(1)), 'c')
call assert_equal(bufname(winbufnr(2)), 'b')
call assert_equal(bufname(winbufnr(3)), 'd')
call assert_equal(bufname(winbufnr(4)), 'a')
call assert_equal(0, win_splitmove(winnr(), winnr('k'), {'vertical': 1}))
call assert_equal(bufname(winbufnr(1)), 'd')
call assert_equal(bufname(winbufnr(2)), 'c')
call assert_equal(bufname(winbufnr(3)), 'b')
call assert_equal(bufname(winbufnr(4)), 'a')
call assert_equal(0, win_splitmove(winnr(), winnr('j'), {'rightbelow': v:true}))
call assert_equal(bufname(winbufnr(1)), 'c')
call assert_equal(bufname(winbufnr(2)), 'b')
call assert_equal(bufname(winbufnr(3)), 'a')
call assert_equal(bufname(winbufnr(4)), 'd')
only | bd
call assert_fails('call win_splitmove(winnr(), 123)', 'E957:')
call assert_fails('call win_splitmove(123, winnr())', 'E957:')
call assert_fails('call win_splitmove(winnr(), winnr())', 'E957:')
endfunc
func Test_window_resize()
" Vertical :resize (absolute, relative, min and max size).
vsplit