Bram,
here is a patch, that allows the setline() functions to remove lines 
after the newly added content. For example you have used setline() to 
add 10 lines to a buffer and later one, you noticed you only want the 
buffer to have 2 lines, you cannot do it without deleting the whole 
buffer using e.g. `:%d` before.

While that is okay for using `setline()` it becomes cumbersome, if one 
needs to do it for the non-current buffer, e.g. using setbufline() it is 
not possible, without manually going to the buffer, deleting it and then 
using setline(). That means, one cannot take advantage of the 
`setbufline()` function at all and might not be possible for timer or 
async functions.

So here is a patch, that allows to remove lines after the newly pasted 
content.

Best,
Christian
-- 
Daß man mit Dienst nach Vorschrift die Urheber der Vorschriften
lächerlich machen kann, ist eine herrliche Pointe der Bürokratie.
                -- Cyril Northcote Parkinson

-- 
-- 
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 c9e44b57ff168d00f637004c3caf146efe724920 Mon Sep 17 00:00:00 2001
From: Christian Brabandt <[email protected]>
Date: Fri, 27 Apr 2018 15:01:19 +0200
Subject: [PATCH] setbufline: allow to remove superflous lines

Currently, setline()/setbufline() can only add new lines to a buffer. If
the buffer does not have enough lines, new lines will be appended as
needed.

However there is no way, to have those lines removed, that are not
needed anymore. So if you have a buffer with 10 lines and you want to
change it to contain only "foo\nbar" and you use
setbufline(bufnr(''), 1, ["foo", "bar"])
you will end up with a buffer containing
,----
| foo
| bar
|
|
|
|
|
|
|
|
`----

So it would be convenient, to have all the rest of the lines after the
buffer being deleted that are not needed anymore. So allow for an
additional flag for the setline()/setbufline() functions that would
delete those lines, e.g. using setbufline(bufnr(''), 1, ["foo", "bar"], 1)
will result in:

,----
| foo
| bar
`----

In addition, add a test, so that the behaviour can be verified.
---
 runtime/doc/eval.txt         | 13 +++++++++----
 src/evalfunc.c               | 33 +++++++++++++++++++++++++++------
 src/testdir/test_bufline.vim |  7 +++++++
 3 files changed, 43 insertions(+), 10 deletions(-)

diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 8961a33c0..d8e9e0303 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -2340,7 +2340,7 @@ searchpos({pattern} [, {flags} [, {stopline} [, {timeout}]]])
 server2client({clientid}, {string})
 				Number	send reply string
 serverlist()			String	get a list of available servers
-setbufline({expr}, {lnum}, {line})
+setbufline({expr}, {lnum}, {line} [, {delete}])
 				Number	set line {lnum} to {line} in buffer
 					{expr}
 setbufvar({expr}, {varname}, {val})
@@ -2348,7 +2348,8 @@ setbufvar({expr}, {varname}, {val})
 setcharsearch({dict})		Dict	set character search from {dict}
 setcmdpos({pos})		Number	set cursor position in command-line
 setfperm({fname}, {mode})	Number	set {fname} file permissions to {mode}
-setline({lnum}, {line})		Number	set line {lnum} to {line}
+setline({lnum}, {line} [, {delete}])
+				Number	set line {lnum} to {line}
 setloclist({nr}, {list} [, {action} [, {what}]])
 				Number	modify location list using {list}
 setmatches({list})		Number	restore a list of matches
@@ -7026,7 +7027,7 @@ serverlist()					*serverlist()*
 		Example: >
 			:echo serverlist()
 <
-setbufline({expr}, {lnum}, {text})			*setbufline()*
+setbufline({expr}, {lnum}, {text} [, {delete}])		*setbufline()*
 		Set line {lnum} to {text} in buffer {expr}.  To insert
 		lines use |append()|.
 
@@ -7035,6 +7036,8 @@ setbufline({expr}, {lnum}, {text})			*setbufline()*
 		{lnum} is used like with |setline()|.
 		This works like |setline()| for the specified buffer.
 		On success 0 is returned, on failure 1 is returned.
+		If {delete} is given and non-zero, all lines below the newly
+		pasted lines, will be removed.
 
 		If {expr} is not a valid buffer or {lnum} is not valid, an
 		error message is given.
@@ -7105,7 +7108,7 @@ setfperm({fname}, {mode})				*setfperm()* *chmod*
 		To read permissions see |getfperm()|.
 
 
-setline({lnum}, {text})					*setline()*
+setline({lnum}, {text} [, {delete}])				*setline()*
 		Set line {lnum} of the current buffer to {text}.  To insert
 		lines use |append()|. To set lines in another buffer use
 		|setbufline()|.
@@ -7113,6 +7116,8 @@ setline({lnum}, {text})					*setline()*
 		{lnum} is used like with |getline()|.
 		When {lnum} is just below the last line the {text} will be
 		added as a new line.
+		When {delete} is given and non-zero, will remove all lines
+                after the newly pasted lines.
 
 		If this succeeds, 0 is returned.  If this fails (most likely
 		because {lnum} is invalid) 1 is returned.
diff --git a/src/evalfunc.c b/src/evalfunc.c
index dd4462d4f..d77870c1b 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -784,12 +784,12 @@ static struct fst
     {"searchpos",	1, 4, f_searchpos},
     {"server2client",	2, 2, f_server2client},
     {"serverlist",	0, 0, f_serverlist},
-    {"setbufline",	3, 3, f_setbufline},
+    {"setbufline",	3, 4, f_setbufline},
     {"setbufvar",	3, 3, f_setbufvar},
     {"setcharsearch",	1, 1, f_setcharsearch},
     {"setcmdpos",	1, 1, f_setcmdpos},
     {"setfperm",	2, 2, f_setfperm},
-    {"setline",		2, 2, f_setline},
+    {"setline",		2, 3, f_setline},
     {"setloclist",	2, 4, f_setloclist},
     {"setmatches",	1, 1, f_setmatches},
     {"setpos",		2, 2, f_setpos},
@@ -10132,9 +10132,11 @@ f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
 
 /*
  * Set line or list of lines in buffer "buf".
+ * Adds content of *lines to buffer buf at line lnum
+ * If delete_rest is set, removes all lines after the newly placed lines
  */
     static void
-set_buffer_lines(buf_T *buf, linenr_T lnum, typval_T *lines, typval_T *rettv)
+set_buffer_lines(buf_T *buf, linenr_T lnum, typval_T *lines, typval_T *rettv, int delete_rest)
 {
     char_u	*line = NULL;
     list_T	*l = NULL;
@@ -10232,6 +10234,17 @@ set_buffer_lines(buf_T *buf, linenr_T lnum, typval_T *lines, typval_T *rettv)
     if (added > 0)
 	appended_lines_mark(lcount, added);
 
+    if (delete_rest)
+    {
+	pos_T	curpos = curwin->w_cursor;
+
+	curwin->w_cursor.lnum = lnum;
+	del_lines(lcount - lnum + 1, TRUE);
+	if (curpos.lnum > curbuf->b_ml.ml_line_count)
+	    curpos.lnum = curbuf->b_ml.ml_line_count;
+	curwin->w_cursor = curpos;
+    }
+
     if (!is_curbuf)
     {
 	curbuf = curbuf_save;
@@ -10249,15 +10262,19 @@ f_setbufline(argvars, rettv)
 {
     linenr_T	lnum;
     buf_T	*buf;
+    unsigned int	delete = FALSE;
 
     buf = get_buf_tv(&argvars[0], FALSE);
+
     if (buf == NULL)
 	rettv->vval.v_number = 1; /* FAIL */
     else
     {
 	lnum = get_tv_lnum_buf(&argvars[1], buf);
+	if (argvars[3].v_type != VAR_UNKNOWN)
+	    delete = (unsigned int)get_tv_number_chk(&argvars[3], NULL);
 
-	set_buffer_lines(buf, lnum, &argvars[2], rettv);
+	set_buffer_lines(buf, lnum, &argvars[2], rettv, delete);
     }
 }
 
@@ -10415,9 +10432,13 @@ f_setfperm(typval_T *argvars, typval_T *rettv)
     static void
 f_setline(typval_T *argvars, typval_T *rettv)
 {
-    linenr_T	lnum = get_tv_lnum(&argvars[0]);
+    linenr_T	    lnum = get_tv_lnum(&argvars[0]);
+    unsigned int    delete = FALSE;
+
+    if (argvars[2].v_type != VAR_UNKNOWN)
+	delete = (unsigned int)get_tv_number_chk(&argvars[2], NULL);
 
-    set_buffer_lines(curbuf, lnum, &argvars[1], rettv);
+    set_buffer_lines(curbuf, lnum, &argvars[1], rettv, delete);
 }
 
 static void set_qf_ll_list(win_T *wp, typval_T *list_arg, typval_T *action_arg, typval_T *what_arg, typval_T *rettv);
diff --git a/src/testdir/test_bufline.vim b/src/testdir/test_bufline.vim
index b886e9950..d1fa7bde7 100644
--- a/src/testdir/test_bufline.vim
+++ b/src/testdir/test_bufline.vim
@@ -10,6 +10,10 @@ func Test_setbufline_getbufline()
   call assert_equal(['foo'], getbufline(b, 1))
   call assert_equal(['bar'], getbufline(b, 2))
   call assert_equal(['foo', 'bar'], getbufline(b, 1, 2))
+  call assert_equal(0, setbufline(b, 1, ['foo'], 1))
+  call assert_equal(['foo'], getbufline(b, 1))
+  call assert_equal([], getbufline(b, 2))
+  call assert_equal(['foo'], getbufline(b, 1, 2))
   exe "bd!" b
   call assert_equal([], getbufline(b, 1, 2))
 
@@ -24,6 +28,9 @@ func Test_setbufline_getbufline()
   call assert_equal(['d'], getbufline(b, 4))
   call assert_equal(['e'], getbufline(b, 5))
   call assert_equal([], getbufline(b, 6))
+  call assert_equal(1, setline(10, ['Z']))
+  call assert_equal(0, setline(1, ['a', 'b'], 1))
+  call assert_equal(['a', 'b'], getline(1, '$'))
   exe "bwipe! " . b
 endfunc
 
-- 
2.16.3

Raspunde prin e-mail lui