Patch 8.1.2020
Problem: It is not easy to change the window layout.
Solution: Add win_splitmove(). (Andy Massimino, closes #4561)
Files: runtime/doc/eval.txt, src/evalfunc.c, src/evalwindow.c,
src/proto/evalwindow.pro, src/testdir/test_window_cmd.vim
*** ../vim-8.1.2019/runtime/doc/eval.txt 2019-09-08 21:51:36.449843947
+0200
--- runtime/doc/eval.txt 2019-09-10 21:15:07.066394525 +0200
***************
*** 2870,2875 ****
--- 2875,2882 ----
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}
***************
*** 10130,10135 ****
--- 10146,10173 ----
Can also be used as a |method|: >
GetWinid()->win_screenpos()
<
+ 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.
+
+ Can also be used as a |method|: >
+ GetWinid()->win_splitmove(target)
+ <
*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
*** ../vim-8.1.2019/src/evalfunc.c 2019-09-08 21:51:36.449843947 +0200
--- src/evalfunc.c 2019-09-10 21:10:59.351329244 +0200
***************
*** 850,855 ****
--- 850,856 ----
{"win_id2tabwin", 1, 1, FEARG_1, f_win_id2tabwin},
{"win_id2win", 1, 1, FEARG_1, f_win_id2win},
{"win_screenpos", 1, 1, FEARG_1, f_win_screenpos},
+ {"win_splitmove", 2, 3, FEARG_1, f_win_splitmove},
{"winbufnr", 1, 1, FEARG_1, f_winbufnr},
{"wincol", 0, 0, 0, f_wincol},
{"winheight", 1, 1, FEARG_1, f_winheight},
*** ../vim-8.1.2019/src/evalwindow.c 2019-09-07 15:45:09.977228927 +0200
--- src/evalwindow.c 2019-09-10 21:21:03.581049143 +0200
***************
*** 744,749 ****
--- 744,835 ----
}
/*
+ * 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 defined(FEAT_GUI)
+ // When 'guioptions' includes 'L' or 'R' may have to remove or add
+ // scrollbars. Have to update them anyway.
+ gui_may_update_scrollbars();
+ #endif
+
+ if (oldwin != curwin)
+ win_goto(oldwin);
+ }
+
+ /*
+ * "win_splitmove()" function
+ */
+ void
+ f_win_splitmove(typval_T *argvars, typval_T *rettv)
+ {
+ 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 (dict_get_number(d, (char_u *)"vertical"))
+ flags |= WSP_VERT;
+ if ((di = dict_find(d, (char_u *)"rightbelow", -1)) != NULL)
+ flags |= tv_get_number(&di->di_tv) ? WSP_BELOW : WSP_ABOVE;
+ size = (int)dict_get_number(d, (char_u *)"size");
+ }
+
+ win_move_into_split(wp, targetwin, size, flags);
+ }
+
+ /*
* "winbufnr(nr)" function
*/
void
*** ../vim-8.1.2019/src/proto/evalwindow.pro 2019-09-07 15:45:09.977228927
+0200
--- src/proto/evalwindow.pro 2019-09-10 21:10:59.351329244 +0200
***************
*** 19,24 ****
--- 19,25 ----
void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
void f_win_id2win(typval_T *argvars, typval_T *rettv);
void f_win_screenpos(typval_T *argvars, typval_T *rettv);
+ void f_win_splitmove(typval_T *argvars, typval_T *rettv);
void f_winbufnr(typval_T *argvars, typval_T *rettv);
void f_wincol(typval_T *argvars, typval_T *rettv);
void f_winheight(typval_T *argvars, typval_T *rettv);
*** ../vim-8.1.2019/src/testdir/test_window_cmd.vim 2019-09-08
21:51:36.453843927 +0200
--- src/testdir/test_window_cmd.vim 2019-09-10 21:21:45.492890991 +0200
***************
*** 857,860 ****
--- 857,893 ----
bwipe!
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
+
" vim: shiftwidth=2 sts=2 expandtab
*** ../vim-8.1.2019/src/version.c 2019-09-09 22:04:19.366736952 +0200
--- src/version.c 2019-09-10 21:22:06.432811971 +0200
***************
*** 759,760 ****
--- 759,762 ----
{ /* Add new patch number below this line */
+ /**/
+ 2020,
/**/
--
You are Dead. Do you wish to restart, load, or quit?
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/vim_dev/201909101923.x8AJNbVt021077%40masaka.moolenaar.net.