# HG changeset patch # User Bram Moolenaar # Date 1329934388 -3600 # Node ID 07fd030f89be62aa11c4ea1a188ee2d8f4348677 # Parent 4a7a394e7afede3e1571d3839dc03a25ade75269 updated for version 7.3.456 Problem: ":tab drop file" has several problems, including moving the current window and opening a new tab for a file that already has a window. Solution: Refactor ":tab drop" handling. (Hirohito Higashi) diff --git a/src/buffer.c b/src/buffer.c --- a/src/buffer.c +++ b/src/buffer.c @@ -4405,7 +4405,12 @@ do_arg_all(count, forceit, keep_tabs) { int i; win_T *wp, *wpnext; - char_u *opened; /* array of flags for which args are open */ + char_u *opened; /* Array of weight for which args are open: + * 0: not opened + * 1: opened in other tab + * 2: opened in curtab + * 3: opened in curtab and curwin + */ int opened_len; /* length of opened[] */ int use_firstwin = FALSE; /* use first window for arglist */ int split_ret = OK; @@ -4414,6 +4419,8 @@ do_arg_all(count, forceit, keep_tabs) buf_T *buf; tabpage_T *tpnext; int had_tab = cmdmod.tab; + win_T *old_curwin, *last_curwin; + tabpage_T *old_curtab, *last_curtab; win_T *new_curwin = NULL; tabpage_T *new_curtab = NULL; @@ -4430,6 +4437,15 @@ do_arg_all(count, forceit, keep_tabs) if (opened == NULL) return; + /* Autocommands may do anything to the argument list. Make sure it's not + * freed while we are working here by "locking" it. We still have to + * watch out for its size to be changed. */ + alist = curwin->w_alist; + ++alist->al_refcount; + + old_curwin = curwin; + old_curtab = curtab; + #ifdef FEAT_GUI need_mouse_correct = TRUE; #endif @@ -4451,36 +4467,51 @@ do_arg_all(count, forceit, keep_tabs) wpnext = wp->w_next; buf = wp->w_buffer; if (buf->b_ffname == NULL - || buf->b_nwindows > 1 + || (!keep_tabs && buf->b_nwindows > 1) #ifdef FEAT_VERTSPLIT || wp->w_width != Columns #endif ) - i = ARGCOUNT; + i = opened_len; else { /* check if the buffer in this window is in the arglist */ - for (i = 0; i < ARGCOUNT; ++i) + for (i = 0; i < opened_len; ++i) { - if (ARGLIST[i].ae_fnum == buf->b_fnum - || fullpathcmp(alist_name(&ARGLIST[i]), - buf->b_ffname, TRUE) & FPC_SAME) + if (i < alist->al_ga.ga_len + && (AARGLIST(alist)[i].ae_fnum == buf->b_fnum + || fullpathcmp(alist_name(&AARGLIST(alist)[i]), + buf->b_ffname, TRUE) & FPC_SAME)) { - if (i < opened_len) + int weight = 1; + + if (old_curtab == curtab) { - opened[i] = TRUE; + ++weight; + if (old_curwin == wp) + ++weight; + } + + if (weight > (int)opened[i]) + { + opened[i] = (char_u)weight; if (i == 0) { + if (new_curwin != NULL) + new_curwin->w_arg_idx = opened_len; new_curwin = wp; new_curtab = curtab; } } - if (wp->w_alist != curwin->w_alist) + else if (keep_tabs) + i = opened_len; + + if (wp->w_alist != alist) { /* Use the current argument list for all windows * containing a file from it. */ alist_unlink(wp->w_alist); - wp->w_alist = curwin->w_alist; + wp->w_alist = alist; ++wp->w_alist->al_refcount; } break; @@ -4489,7 +4520,7 @@ do_arg_all(count, forceit, keep_tabs) } wp->w_arg_idx = i; - if (i == ARGCOUNT && !keep_tabs) /* close this window */ + if (i == opened_len && !keep_tabs)/* close this window */ { if (P_HID(buf) || forceit || buf->b_nwindows > 1 || !bufIsChanged(buf)) @@ -4511,7 +4542,8 @@ do_arg_all(count, forceit, keep_tabs) } #ifdef FEAT_WINDOWS /* don't close last window */ - if (firstwin == lastwin && first_tabpage->tp_next == NULL) + if (firstwin == lastwin + && (first_tabpage->tp_next == NULL || !had_tab)) #endif use_firstwin = TRUE; #ifdef FEAT_WINDOWS @@ -4545,20 +4577,16 @@ do_arg_all(count, forceit, keep_tabs) * Open a window for files in the argument list that don't have one. * ARGCOUNT may change while doing this, because of autocommands. */ - if (count > ARGCOUNT || count <= 0) - count = ARGCOUNT; - - /* Autocommands may do anything to the argument list. Make sure it's not - * freed while we are working here by "locking" it. We still have to - * watch out for its size to be changed. */ - alist = curwin->w_alist; - ++alist->al_refcount; + if (count > opened_len || count <= 0) + count = opened_len; #ifdef FEAT_AUTOCMD /* Don't execute Win/Buf Enter/Leave autocommands here. */ ++autocmd_no_enter; ++autocmd_no_leave; #endif + last_curwin = curwin; + last_curtab = curtab; win_enter(lastwin, FALSE); #ifdef FEAT_WINDOWS /* ":drop all" should re-use an empty window to avoid "--remote-tab" @@ -4568,11 +4596,11 @@ do_arg_all(count, forceit, keep_tabs) use_firstwin = TRUE; #endif - for (i = 0; i < count && i < alist->al_ga.ga_len && !got_int; ++i) + for (i = 0; i < count && i < opened_len && !got_int; ++i) { if (alist == &global_alist && i == global_alist.al_ga.ga_len - 1) arg_had_last = TRUE; - if (i < opened_len && opened[i]) + if (opened[i] > 0) { /* Move the already present window to below the current window */ if (curwin->w_arg_idx != i) @@ -4581,7 +4609,13 @@ do_arg_all(count, forceit, keep_tabs) { if (wpnext->w_arg_idx == i) { - win_move_after(wpnext, curwin); + if (keep_tabs) + { + new_curwin = wpnext; + new_curtab = curtab; + } + else + win_move_after(wpnext, curwin); break; } } @@ -4636,6 +4670,14 @@ do_arg_all(count, forceit, keep_tabs) #ifdef FEAT_AUTOCMD --autocmd_no_enter; #endif + /* restore last referenced tabpage's curwin */ + if (last_curtab != new_curtab) + { + if (valid_tabpage(last_curtab)) + goto_tabpage_tp(last_curtab); + if (win_valid(last_curwin)) + win_enter(last_curwin, FALSE); + } /* to window with first arg */ if (valid_tabpage(new_curtab)) goto_tabpage_tp(new_curtab); diff --git a/src/testdir/test62.in b/src/testdir/test62.in --- a/src/testdir/test62.in +++ b/src/testdir/test62.in @@ -50,6 +50,43 @@ STARTTEST :call append(line('$'), test_status) :" :" +:" Test for ":tab drop exist-file" to keep current window. +:sp test1 +:tab drop test1 +:let test_status = 'tab drop 1: fail' +:if tabpagenr('$') == 1 && winnr('$') == 2 && winnr() == 1 +: let test_status = 'tab drop 1: pass' +:endif +:close +:call append(line('$'), test_status) +:" +:" +:" Test for ":tab drop new-file" to keep current window of tabpage 1. +:split +:tab drop newfile +:let test_status = 'tab drop 2: fail' +:if tabpagenr('$') == 2 && tabpagewinnr(1, '$') == 2 && tabpagewinnr(1) == 1 +: let test_status = 'tab drop 2: pass' +:endif +:tabclose +:q +:call append(line('$'), test_status) +:" +:" +:" Test for ":tab drop multi-opend-file" to keep current tabpage and window. +:new test1 +:tabnew +:new test1 +:tab drop test1 +:let test_status = 'tab drop 3: fail' +:if tabpagenr() == 2 && tabpagewinnr(2, '$') == 2 && tabpagewinnr(2) == 1 +: let test_status = 'tab drop 3: pass' +:endif +:tabclose +:q +:call append(line('$'), test_status) +:" +:" :/^Results/,$w! test.out :qa! ENDTEST diff --git a/src/testdir/test62.ok b/src/testdir/test62.ok --- a/src/testdir/test62.ok +++ b/src/testdir/test62.ok @@ -5,3 +5,6 @@ this is tab page 1 this is tab page 4 gettabvar: pass settabvar: pass +tab drop 1: pass +tab drop 2: pass +tab drop 3: pass diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -715,6 +715,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 456, +/**/ 455, /**/ 454,