To: vim_dev@googlegroups.com Subject: Patch 8.1.2020 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 -- Bram@Moolenaar.net -- 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 ///