On Mi, 06 Jan 2016, Christian Brabandt wrote:

> Here is a patch series, that adds the <restore> argument to the 
> :windo/bufdo/argdo/cdo commands that should correctly restore the cursor 
> position after those commands. The patch includes updates to the 
> documentation, a newstyle test and an update to the matchparen plugin, 
> that initially caused the trouble.
> 
> Instead of sending one single patch, I decided to practice my git skills 
> and created a patch series. That should be easier to review. Let's see 
> how well this works.

And this time, also include the newstyle test.


Best,
Christian
-- 
"Ich bin über die Wurzeln des Baumes gestolpert, den ich 
gepflanzt hatte." Das muss ein alter Forstmann gewesen sein, der dies 
gesagt hat.
                -- Goethe, Maximen und Reflektionen, Nr. 547

-- 
-- 
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].
For more options, visit https://groups.google.com/d/optout.
From ff47b3969704128e611abd6b3a011d4d501b0756 Mon Sep 17 00:00:00 2001
From: Christian Brabandt <[email protected]>
Date: Tue, 5 Jan 2016 21:09:00 +0100
Subject: [PATCH 1/6] remove bang attribute from :windo command

documentation does not allow ! for the :windo command. However, Vim
allows to call :windo! commands.

The bang attribute does seem to be not used, so remove it from the
command definition.

Signed-off-by: Christian Brabandt <[email protected]>
---
 src/ex_cmds.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/ex_cmds.h b/src/ex_cmds.h
index 4b5f684..ed24c54 100644
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -1592,7 +1592,7 @@ EX(CMD_wincmd,		"wincmd",	ex_wincmd,
 			NEEDARG|WORD1|RANGE|NOTADR,
 			ADDR_WINDOWS),
 EX(CMD_windo,		"windo",	ex_listdo,
-			BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,
+			NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,
 			ADDR_WINDOWS),
 EX(CMD_winpos,		"winpos",	ex_winpos,
 			EXTRA|TRLBAR|CMDWIN,
-- 
2.1.4

From 89abbfa62657eff66483d396de3365cf0b3ebd5d Mon Sep 17 00:00:00 2001
From: Christian Brabandt <[email protected]>
Date: Tue, 5 Jan 2016 20:49:00 +0100
Subject: [PATCH 2/6] enable windo/argdo/bufdo <restore> command

Using the <restore> argument to the :*do commands makes sure, that after
executing those commands the cursor will be back in the original windo.

Signed-off-by: Christian Brabandt <[email protected]>
---
 src/ex_cmds2.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c
index 05baa7e..229f689 100644
--- a/src/ex_cmds2.c
+++ b/src/ex_cmds2.c
@@ -2439,6 +2439,17 @@ ex_listdo(eap)
     exarg_T	*eap;
 {
     int		i;
+    int		restore = FALSE;
+    struct	st_restore
+    {
+	int	i;
+	buf_T	*curbuf;
+#ifdef FEAT_WINDOWS
+	win_T	*curwin;
+	tabpage_T   *curtab;
+#endif
+    } rst;
+
 #ifdef FEAT_WINDOWS
     win_T	*wp;
     tabpage_T	*tp;
@@ -2472,6 +2483,26 @@ ex_listdo(eap)
     start_global_changes();
 #endif
 
+    skipwhite(eap->arg);
+    if (STRNCMP(eap->arg, "<restore>", 9) == 0)
+    {
+	eap->arg = skipwhite(eap->arg + 9);
+	restore = TRUE;
+	rst.i = 0;
+	rst.curbuf = curbuf;
+#ifdef FEAT_WINDOWS
+	rst.curwin = curwin;
+	rst.curtab = curtab;
+#endif
+	if (eap->cmdidx == CMD_argdo)
+	    rst.i = curwin->w_arg_idx;
+#ifdef FEAT_QUICKFIX
+	if (eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo
+		|| eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo)
+	    rst.i = qf_get_cur_idx(eap);
+#endif
+    }
+
     if (eap->cmdidx == CMD_windo
 	    || eap->cmdidx == CMD_tabdo
 	    || P_HID(curbuf)
@@ -2664,6 +2695,33 @@ ex_listdo(eap)
 	listcmd_busy = FALSE;
     }
 
+    if (restore)
+    {
+	if (eap->cmdidx == CMD_bufdo && buf_valid(rst.curbuf))
+		goto_buffer(eap, DOBUF_FIRST, FORWARD, rst.curbuf->b_fnum);
+#ifdef FEAT_WINDOWS
+	else if (eap->cmdidx == CMD_windo && win_valid(rst.curwin))
+		win_goto(rst.curwin);
+	else if (eap->cmdidx == CMD_tabdo && valid_tabpage(tp))
+		goto_tabpage_tp(rst.curtab, TRUE, TRUE);
+#endif
+	else if (eap->cmdidx == CMD_argdo)
+	{
+	    if (curwin->w_arg_idx != rst.i || !editing_arg_idx(rst.curwin))
+		do_argfile(eap, rst.i);
+	}
+#ifdef FEAT_QUICKFIX
+	else if (eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo
+		|| eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo)
+	{
+	    eap->addr_count = rst.i;
+	    eap->line1 = rst.i;
+	    ex_cc(eap);
+	}
+#endif
+    }
+
+
 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
     if (save_ei != NULL)
     {
-- 
2.1.4

From a374a1a06bc06cdaa39fda4d12471678e1d19808 Mon Sep 17 00:00:00 2001
From: Christian Brabandt <[email protected]>
Date: Wed, 6 Jan 2016 08:49:00 +0100
Subject: [PATCH 3/6] correctly reset view on buffer

After resetting the cursor to the correct location, also make sure, the
viewport to the windo stays the same.

This should make sure, that the user does not notice any movement to the
viewport.

Signed-off-by: Christian Brabandt <[email protected]>
---
 src/ex_cmds2.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c
index 229f689..148c54c 100644
--- a/src/ex_cmds2.c
+++ b/src/ex_cmds2.c
@@ -2448,6 +2448,19 @@ ex_listdo(eap)
 	win_T	*curwin;
 	tabpage_T   *curtab;
 #endif
+	/* cursor positioning */
+	linenr_T    lnum;
+	colnr_T	    col;
+#ifdef FEAT_VIRTUALEDIT
+	colnr_T	    coladd;
+#endif
+	colnr_T	    curswant;
+	linenr_T    topline;
+#ifdef FEAT_DIFF
+	int	    topfill;
+#endif
+	colnr_T	    leftcol;
+	colnr_T	    skipcol;
     } rst;
 
 #ifdef FEAT_WINDOWS
@@ -2501,6 +2514,18 @@ ex_listdo(eap)
 		|| eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo)
 	    rst.i = qf_get_cur_idx(eap);
 #endif
+	rst.lnum = curwin->w_cursor.lnum;
+	rst.col  = curwin->w_cursor.col;
+#ifdef FEAT_VIRTUALEDIT
+	rst.coladd = curwin->w_cursor.coladd;
+#endif
+	rst.curswant = curwin->w_curswant;
+	rst.topline  = curwin->w_topline;
+#ifdef FEAT_DIFF
+	rst.topfill = curwin->w_topfill;
+#endif
+	rst.leftcol = curwin->w_leftcol;
+	rst.skipcol = curwin->w_skipcol;
     }
 
     if (eap->cmdidx == CMD_windo
@@ -2717,8 +2742,37 @@ ex_listdo(eap)
 	    eap->addr_count = rst.i;
 	    eap->line1 = rst.i;
 	    ex_cc(eap);
+	    if (buf_valid(rst.curbuf))
+		goto_buffer(eap, DOBUF_FIRST, FORWARD, rst.curbuf->b_fnum);
 	}
 #endif
+	curwin->w_cursor.lnum = rst.lnum;
+	curwin->w_cursor.col  = rst.col;
+#ifdef FEAT_VIRTUALEDIT
+	curwin->w_cursor.coladd = rst.coladd;
+#endif
+	curwin->w_curswant = rst.curswant;
+	curwin->w_set_curswant = FALSE;
+	set_topline(curwin, rst.topline);
+#ifdef FEAT_DIFF
+	curwin->w_topfill = rst.topfill;
+#endif
+	curwin->w_leftcol = rst.leftcol;
+	curwin->w_skipcol = rst.skipcol;
+	check_cursor();
+	win_new_height(curwin, curwin->w_height);
+# ifdef FEAT_VERTSPLIT
+	win_new_width(curwin, W_WIDTH(curwin));
+# endif
+	changed_window_setting();
+
+	if (curwin->w_topline <= 0)
+	    curwin->w_topline = 1;
+	if (curwin->w_topline > curbuf->b_ml.ml_line_count)
+	    curwin->w_topline = curbuf->b_ml.ml_line_count;
+#ifdef FEAT_DIFF
+	check_topfill(curwin, TRUE);
+#endif
     }
 
 
-- 
2.1.4

From 7cad5d2f3319d141173e8dcbe9e0b4f1939889b0 Mon Sep 17 00:00:00 2001
From: Christian Brabandt <[email protected]>
Date: Wed, 6 Jan 2016 08:55:54 +0100
Subject: [PATCH 4/6] add tests for windo/argdo/listdo <restore> commands

Tests the :windo/argdo/cdo command using the <restore> syntax.

A newstyle test is created.

Signed-off-by: Christian Brabandt <[email protected]>
---
 src/testdir/Make_all.mak      |   3 +-
 src/testdir/test_listcmds.vim | 136 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 138 insertions(+), 1 deletion(-)
 create mode 100644 src/testdir/test_listcmds.vim

diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak
index 2ad039c..6739a0d 100644
--- a/src/testdir/Make_all.mak
+++ b/src/testdir/Make_all.mak
@@ -176,7 +176,8 @@ NEW_TESTS = test_assert.res \
 	    test_cdo.res \
 	    test_quickfix.res \
 	    test_viml.res \
-	    test_alot.res
+	    test_alot.res \
+	    test_listcmds.res
 
 
 # Explicit dependencies.
diff --git a/src/testdir/test_listcmds.vim b/src/testdir/test_listcmds.vim
new file mode 100644
index 0000000..4973c4c
--- /dev/null
+++ b/src/testdir/test_listcmds.vim
@@ -0,0 +1,136 @@
+  " Test for :windo/:bufdo/:argdo/:cdo/:cfdo/:ldo/:lfdo commnads and the <restore>
+  " argument
+
+  func SetUp() "{{{1
+    call writefile(['foobar1'], 'foobar1.txt')
+    call writefile(['foobar2']+range(1,15), 'foobar2.txt')
+    call writefile(['foobar3'], 'foobar3.txt')
+  endfu
+
+  func s:Arglist() "{{{1
+    redir => arg | sil args | redir end
+    return arg
+  endfu
+
+  func TestDown() "{{{1
+    for i in range(1,3)
+    call delete('foobar'.i.'.txt')
+  endfu
+
+  func Test_windo() "{{{1
+    if !has("windows")
+      return
+    endif
+    e foobar1.txt
+    sp foobar2.txt | norm! 15zt$
+    sp foobar3.txt
+    1wincmd w
+    windo sil echo 1
+    " Cursor should be in last window: 3
+    call assert_equal(3, winnr())
+    1,2windo sil echo 1
+    " Cursor should be in 2 window: 2
+    call assert_equal(2,winnr())
+    2wincmd w
+    let a=winsaveview()
+    windo <restore> sil echo 1
+    " Cursor should be in 2 window: 2
+    call assert_equal(2,winnr())
+    call assert_equal(a, winsaveview())
+    %bw!
+  endfunc
+
+  func Test_bufdo() "{{{1
+    let startnr = bufnr('')
+    e foobar1.txt
+    e foobar2.txt
+    e foobar3.txt
+    let endnr = bufnr('$')
+    " Cursor in last buffer
+    call assert_equal(startnr+2, endnr)
+    bufdo sil echo 1
+    " Cursor in last buffer
+    call assert_equal(endnr, bufnr(''))
+    exe printf(":%d,%dbufdo sil echo 1", startnr+1, startnr+2)
+    " Cursor in second last buffer
+    call assert_equal(endnr, bufnr(''))
+    exe startnr+2."b"
+    set modified
+    try
+      bufdo sil echo 1
+    catch /^Vim\%((\a\+)\)\=:E37/
+    endtry
+    set nomodified
+    " cursor still in the same buffer
+    call assert_equal(startnr+2, bufnr(''))
+    bufdo! sil echo 1
+    " aborted modified buffer, cursor in last buffer
+    call assert_equal(endnr, bufnr(''))
+    exe startnr+2."b"
+    norm! 15zt$
+    let a=winsaveview()
+    bufdo <restore> sil echo 1
+    call assert_equal(startnr+2, bufnr(''))
+    call assert_equal(a, winsaveview())
+    %bw!
+  endfu
+
+  func Test_argdo() "{{{1
+    let startnr = bufnr('')
+    argadd f*.txt
+    let endnr = bufnr('$')
+    first
+    call assert_equal(startnr, bufnr(''))
+    set modified
+    try
+      argdo :sil echo 1
+    catch /^Vim\%((\a\+)\)\=:E37/
+      set nomodified
+    endtry
+    let args=s:Arglist()
+    call assert_equal(startnr, bufnr(''))
+    argdo :sil echo 1
+    call assert_equal(endnr, bufnr(''))
+    call assert_true(args isnot# s:Arglist())
+    first
+    next
+    let args=s:Arglist()
+    let curbuf = bufnr('')
+    let a=winsaveview()
+    argdo <restore> sil echo 1
+    call assert_equal(curbuf, bufnr(''))
+    call assert_equal(a, winsaveview())
+    call assert_equal(args, s:Arglist())
+    set modified
+    try
+      argdo :sil echo 1
+    catch /^Vim\%((\a\+)\)\=:E37/
+      set nomodified
+    endtry
+    call assert_equal(curbuf, bufnr(''))
+    call assert_equal(a, winsaveview())
+    %bw!
+  endfu
+
+  func Test_qdo() "{{{1
+    let startnr = bufnr('')
+    vimgrep /foobar/j f*.txt
+    let endnr = bufnr('$')
+    copen
+    wincmd w
+    call assert_equal(startnr, bufnr(''))
+    cnext
+    call assert_equal(startnr+2, bufnr(''))
+    cdo sil echo 1
+    call assert_equal(endnr, bufnr(''))
+    exe startnr+2.'b'
+    norm! 15zt$
+    let a=winsaveview()
+    cdo <restore> sil echo 1
+    call assert_equal(startnr+2, bufnr(''))
+    call assert_equal(a, winsaveview())
+    cclose
+    %bw!
+  endfu
+
+" vim: tabstop=2 shiftwidth=0 expandtab
-- 
2.1.4

From 20936a269020e86c593454805a6c42770b042a4d Mon Sep 17 00:00:00 2001
From: Christian Brabandt <[email protected]>
Date: Tue, 5 Jan 2016 21:10:14 +0100
Subject: [PATCH 5/6] updated documentation

Also update the documentation to mention the <restore> attribute.

Signed-off-by: Christian Brabandt <[email protected]>
---
 runtime/doc/editing.txt  |  5 +++++
 runtime/doc/quickfix.txt | 16 ++++++++++++----
 runtime/doc/tabpage.txt  |  4 ++++
 runtime/doc/windows.txt  | 12 ++++++++++--
 4 files changed, 31 insertions(+), 6 deletions(-)

diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt
index 1d104bc..1fcf9ce 100644
--- a/runtime/doc/editing.txt
+++ b/runtime/doc/editing.txt
@@ -873,6 +873,11 @@ USING THE ARGUMENT LIST
 			Also see |:windo|, |:tabdo|, |:bufdo|, |:cdo|, |:ldo|,
 			|:cfdo| and |:lfdo|
 
+						*:argdo-<restore>*
+:[range]argdo[!] <restore> {cmd}
+			Like |:argdo| but restore position in the argument
+			list afterwards.
+
 Example: >
 	:args *.c
 	:argdo set ff=unix | update
diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt
index 674470e..5536e50 100644
--- a/runtime/doc/quickfix.txt
+++ b/runtime/doc/quickfix.txt
@@ -301,7 +301,8 @@ use this code: >
 
 EXECUTE A COMMAND IN ALL THE BUFFERS IN QUICKFIX OR LOCATION LIST:
 							*:cdo*
-:cdo[!] {cmd}		Execute {cmd} in each valid entry in the quickfix list.
+:cdo[!] [<restore>] {cmd}
+			Execute {cmd} in each valid entry in the quickfix list.
 			It works like doing this: >
 				:cfirst
 				:{cmd}
@@ -320,6 +321,10 @@ EXECUTE A COMMAND IN ALL THE BUFFERS IN QUICKFIX OR LOCATION LIST:
 				:10,$cdo cmd
 <			To skip entries 1 to 9.
 
+			If the <restore> argument is given, the quickfix
+			position will be restored after the {cmd} has been
+			finished.
+
 			Note: While this command is executing, the Syntax
 			autocommand event is disabled by adding it to
 			'eventignore'.  This considerably speeds up editing
@@ -330,7 +335,8 @@ EXECUTE A COMMAND IN ALL THE BUFFERS IN QUICKFIX OR LOCATION LIST:
 			|:ldo|, |:cfdo| and |:lfdo|.
 
 							*:cfdo*
-:cfdo[!] {cmd}		Execute {cmd} in each file in the quickfix list.
+:cfdo[!] [<restore>] {cmd}
+			Execute {cmd} in each file in the quickfix list.
 			It works like doing this: >
 				:cfirst
 				:{cmd}
@@ -342,7 +348,8 @@ EXECUTE A COMMAND IN ALL THE BUFFERS IN QUICKFIX OR LOCATION LIST:
 			|+listcmds| feature}
 
 							*:ldo*
-:ld[o][!] {cmd}		Execute {cmd} in each valid entry in the location list
+:ld[o][!] [<restore>] {cmd}
+			Execute {cmd} in each valid entry in the location list
 			for the current window.
 			It works like doing this: >
 				:lfirst
@@ -356,7 +363,8 @@ EXECUTE A COMMAND IN ALL THE BUFFERS IN QUICKFIX OR LOCATION LIST:
 			|+listcmds| feature}
 
 							*:lfdo*
-:lfdo[!] {cmd}		Execute {cmd} in each file in the location list for
+:lfdo[!] [<restore>] {cmd}
+			Execute {cmd} in each file in the location list for
 			the current window.
 			It works like doing this: >
 				:lfirst
diff --git a/runtime/doc/tabpage.txt b/runtime/doc/tabpage.txt
index b98c18b..17e71e5 100644
--- a/runtime/doc/tabpage.txt
+++ b/runtime/doc/tabpage.txt
@@ -251,6 +251,10 @@ LOOPING OVER TAB PAGES:
 		Also see |:windo|, |:argdo|, |:bufdo|, |:cdo|, |:ldo|, |:cfdo|
 		and |:lfdo|
 
+:[range]tabd[o] <restore> {cmd}
+		Like |:tabdo| but restore cursor to the tabpage from which
+		this command was called.
+
 ==============================================================================
 3. Other items						*tab-page-other*
 
diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt
index f6e0a1f..bc25c39 100644
--- a/runtime/doc/windows.txt
+++ b/runtime/doc/windows.txt
@@ -718,6 +718,10 @@ can also get to them with the buffer list commands, like ":bnext".
 			Also see |:tabdo|, |:argdo|, |:bufdo|, |:cdo|, |:ldo|,
 			|:cfdo| and |:lfdo|
 
+:[range]windo <restore> {cmd}
+			Like *:windo* but restore cursor to the window where it
+			was started.
+
 							*:bufdo*
 :[range]bufdo[!] {cmd}	Execute {cmd} in each buffer in the buffer list or if
 			[range] is given only for buffers for which their
@@ -747,11 +751,15 @@ can also get to them with the buffer list commands, like ":bnext".
 			Also see |:tabdo|, |:argdo|, |:windo|, |:cdo|, |:ldo|,
 			|:cfdo| and |:lfdo|
 
+:[range]bufdo[!] <restore> {cmd}
+			Like *:bufdo* but restore the buffer afterwards.
+
 Examples: >
 
-	:windo set nolist nofoldcolumn | normal zn
+	:windo <restore> set nolist nofoldcolumn | normal zn
 
-This resets the 'list' option and disables folding in all windows. >
+This resets the 'list' option and disables folding in all windows, cursor will
+be in the same window from which this command was called. >
 
 	:bufdo set fileencoding= | update
 
-- 
2.1.4

From 4c6ebf94e5a82e439fbd945ad0359d3cce50bc3e Mon Sep 17 00:00:00 2001
From: Christian Brabandt <[email protected]>
Date: Wed, 6 Jan 2016 09:19:18 +0100
Subject: [PATCH 6/6] matchparen plugin use the <restore> attribute to :windo

This should prevent nasty side effects in other plugins that make use of
the matchparen plugin (e.g. the LargeFile) plugin, which do not note,
that using the DoMatchParen command might actually change the current
window and buffer.

So make sure, that after calling the matchparen command, the cursor
position has been restored

Signed-off-by: Christian Brabandt <[email protected]>
---
 runtime/plugin/matchparen.vim | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/runtime/plugin/matchparen.vim b/runtime/plugin/matchparen.vim
index 873302e..ea3d7a8 100644
--- a/runtime/plugin/matchparen.vim
+++ b/runtime/plugin/matchparen.vim
@@ -186,9 +186,9 @@ function! s:Highlight_Matching_Pair()
 endfunction
 
 " Define commands that will disable and enable the plugin.
-command! NoMatchParen windo silent! call matchdelete(3) | unlet! g:loaded_matchparen |
+command! NoMatchParen windo <restore> silent! call matchdelete(3) | unlet! g:loaded_matchparen |
 	  \ au! matchparen
-command! DoMatchParen runtime plugin/matchparen.vim | windo doau CursorMoved
+command! DoMatchParen runtime plugin/matchparen.vim | windo <restore> doau CursorMoved
 
 let &cpo = s:cpo_save
 unlet s:cpo_save
-- 
2.1.4

Raspunde prin e-mail lui