Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add split-move wincmds g[hjkl]
  • Loading branch information
andymass committed Jul 15, 2018
1 parent 2196bca commit 54ae8fe
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 12 deletions.
34 changes: 32 additions & 2 deletions runtime/doc/windows.txt
Expand Up @@ -502,15 +502,45 @@ CTRL-W H Move the current window to be at the far left, using the
current window and then creating another one with
":vert topleft split", except that the current window contents
is used for the new window.
{not available when compiled without the |+vertsplit| feature}

*CTRL-W_L*
CTRL-W L Move the current window to be at the far right, using the full
height of the screen. This works like closing the
current window and then creating another one with
":vert botright split", except that the current window
contents is used for the new window.
{not available when compiled without the |+vertsplit| feature}

*CTRL-W_gk*
CTRL-W g k Move the current window to a new vertical split of the window
above the current window. This is similar to using |CTRL-W_k|
to move to a different window, creating a new split using
":vsplit" but having the same contents as the previous window,
and then closing the previous window. If there is no window
above the current window, this behaves like |CTRL-W_K|.

*CTRL-W_gj*
CTRL-W g j Move the current window to a new vertical split of the window
above the current window. This is similar to using |CTRL-W_j|
to move to a different window, creating a new split with
":vsplit" but having the same contents as the previous window,
and then closing the previous window. If there is no window
below the current window, this behaves like |CTRL-W_J|.

*CTRL-W_gh*
CTRL-W g h Move the current window to a new horizontal split of the window
left of the current window. This is similar to using |CTRL-W_h|
to move to a different window, creating a new split with
":vsplit" but having the same contents as the previous window,
and then closing the previous window. If there is no window
to the left of the current window, this behaves like |CTRL-W_H|.

*CTRL-W_gl*
CTRL-W g l Move the current window to a new horizontal split of the window
right of the current window. This is similar to using |CTRL-W_l|
to move to a different window, creating a new split with
":vsplit" but having the same contents as the previous window,
and then closing the previous window. If there is no window
to the right of the current window, this behaves like |CTRL-W_L|.

*CTRL-W_T*
CTRL-W T Move the current window to a new tab page. This fails if
Expand Down
2 changes: 2 additions & 0 deletions src/proto/window.pro
Expand Up @@ -37,6 +37,8 @@ void tabpage_move(int nr);
void win_goto(win_T *wp);
win_T *win_find_nr(int winnr);
tabpage_T *win_find_tabpage(win_T *win);
win_T *win_ver_neighbor(tabpage_T *tp, win_T *wp, int up, long count);
win_T *win_hor_neighbor(tabpage_T *tp, win_T *wp, int left, long count);
void win_enter(win_T *wp, int undo_sync);
win_T *buf_jump_open_win(buf_T *buf);
win_T *buf_jump_open_tab(buf_T *buf);
Expand Down
28 changes: 28 additions & 0 deletions src/testdir/test_window_cmd.vim
Expand Up @@ -522,4 +522,32 @@ func Test_winrestcmd()
only
endfunc

func Test_win_splitmove()
edit a
leftabove split b
leftabove vsplit c
leftabove split d
wincmd gl
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')
wincmd gj
wincmd gj
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')
wincmd gk
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')
wincmd gh
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')
endfunc

" vim: shiftwidth=2 sts=2 expandtab
145 changes: 135 additions & 10 deletions src/window.c
Expand Up @@ -19,6 +19,7 @@ static void frame_setwidth(frame_T *curfrp, int width);
static void win_exchange(long);
static void win_rotate(int, int);
static void win_totop(int size, int flags);
static void win_moveinto(int size, int vert, int above);
static void win_equal_rec(win_T *next_curwin, int current, frame_T *topfr, int dir, int col, int row, int width, int height);
static int last_window(void);
static int close_last_window_tabpage(win_T *win, int free_buf, tabpage_T *prev_curtab);
Expand Down Expand Up @@ -586,6 +587,17 @@ do_window(
nchar = xchar;
goto wingotofile;
#endif

/* move window into another window */
case 'k':
case 'j':
case 'h':
case 'l':
CHECK_CMDWIN;
win_moveinto((int)Prenum, xchar == 'h' || xchar == 'l',
xchar == 'h' || xchar == 'k');
break;

default:
beep_flush();
break;
Expand Down Expand Up @@ -1701,6 +1713,91 @@ win_totop(int size, int flags)
#endif
}

/*
* Move the current window into a split of the window in a given direction
*/
static void
win_moveinto(int size, int vert, int above)
{
int dir;
int flags;
win_T *targetwin;
win_T *wp;
int height = curwin->w_height;

if (ONE_WINDOW)
{
beep_flush();
return;
}

/* Target window is the neighbor in the wincmd h,j,k,l direction */
if (vert)
targetwin = win_hor_neighbor(curtab, curwin, above, 1);
else
targetwin = win_ver_neighbor(curtab, curwin, above, 1);

/* If no target window, behave like wincmd H,J,K,L */
if (targetwin == curwin)
{
win_totop(size, (vert ? WSP_VERT : 0)
| (above ? WSP_TOP : WSP_BOT));
return;
}

/* Make the split left/above depending on relative positions;
* - If the current window is at least as big as the target then
* compare the cursor position and the midpoint of the target window
* - If the current window is smaller than the target
* then compare the midpoints of the current and target windows */
if (vert)
{
if (curwin->w_winrow +
(curwin->w_height >= targetwin->w_height
? curwin->w_wrow : curwin->w_height / 2)
<= targetwin->w_winrow + targetwin->w_height / 2)
flags = WSP_ABOVE;
else
flags = WSP_BELOW;
}
else
{
if (curwin->w_wincol +
(curwin->w_width >= targetwin->w_width
? curwin->w_wcol : curwin->w_width / 2)
<= targetwin->w_wincol + targetwin->w_width / 2)
flags = WSP_VERT | WSP_ABOVE;
else
flags = WSP_VERT | WSP_BELOW;
}

/* Jump to the new window but remember the current one */
wp = curwin;
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 (!(flags & WSP_VERT))
{
win_setheight(height);
if (p_ea)
win_equal(curwin, 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
}

/*
* Move window "win1" to below/right of "win2" and make "win1" the current
* window. Only works within the same frame!
Expand Down Expand Up @@ -4227,12 +4324,27 @@ win_find_tabpage(win_T *win)
win_goto_ver(
int up, /* TRUE to go to win above */
long count)
{
win_T *wp = win_ver_neighbor(curtab, curwin, up, count);
if (wp != NULL)
win_goto(wp);
}

/*
* Get the above or below neighbor of the specified window.
*/
win_T *
win_ver_neighbor(
tabpage_T *tp,
win_T *wp,
int up, /* TRUE to find win above */
long count)
{
frame_T *fr;
frame_T *nfr;
frame_T *foundfr;

foundfr = curwin->w_frame;
foundfr = wp->w_frame;
while (count--)
{
/*
Expand All @@ -4242,7 +4354,7 @@ win_goto_ver(
fr = foundfr;
for (;;)
{
if (fr == topframe)
if (fr == tp->tp_topframe)
goto end;
if (up)
nfr = fr->fr_prev;
Expand All @@ -4269,7 +4381,7 @@ win_goto_ver(
/* Find the frame at the cursor row. */
while (fr->fr_next != NULL
&& frame2win(fr)->w_wincol + fr->fr_width
<= curwin->w_wincol + curwin->w_wcol)
<= wp->w_wincol + wp->w_wcol)
fr = fr->fr_next;
}
if (nfr->fr_layout == FR_COL && up)
Expand All @@ -4279,8 +4391,7 @@ win_goto_ver(
}
}
end:
if (foundfr != NULL)
win_goto(foundfr->fr_win);
return foundfr != NULL ? foundfr->fr_win : NULL;
}

/*
Expand All @@ -4290,12 +4401,27 @@ win_goto_ver(
win_goto_hor(
int left, /* TRUE to go to left win */
long count)
{
win_T *wp = win_hor_neighbor(curtab, curwin, left, count);
if (wp != NULL)
win_goto(wp);
}

/*
* Get the left or right neighbor of the specified window.
*/
win_T *
win_hor_neighbor(
tabpage_T *tp,
win_T *wp,
int left, /* TRUE to find left win */
long count)
{
frame_T *fr;
frame_T *nfr;
frame_T *foundfr;

foundfr = curwin->w_frame;
foundfr = wp->w_frame;
while (count--)
{
/*
Expand All @@ -4305,7 +4431,7 @@ win_goto_hor(
fr = foundfr;
for (;;)
{
if (fr == topframe)
if (fr == tp->tp_topframe)
goto end;
if (left)
nfr = fr->fr_prev;
Expand All @@ -4332,7 +4458,7 @@ win_goto_hor(
/* Find the frame at the cursor row. */
while (fr->fr_next != NULL
&& frame2win(fr)->w_winrow + fr->fr_height
<= curwin->w_winrow + curwin->w_wrow)
<= wp->w_winrow + wp->w_wrow)
fr = fr->fr_next;
}
if (nfr->fr_layout == FR_ROW && left)
Expand All @@ -4342,8 +4468,7 @@ win_goto_hor(
}
}
end:
if (foundfr != NULL)
win_goto(foundfr->fr_win);
return foundfr != NULL ? foundfr->fr_win : NULL;
}

/*
Expand Down

0 comments on commit 54ae8fe

Please sign in to comment.