Skip to content

Commit b31cf2b

Browse files
committed
patch 8.0.1039: cannot change a line in not current buffer
Problem: Cannot change a line in a buffer other than the current one. Solution: Add setbufline(). (Yasuhiro Matsumoto, Ozaki Kiichi, closes #1953)
1 parent cf4b00c commit b31cf2b

6 files changed

Lines changed: 167 additions & 67 deletions

File tree

runtime/doc/eval.txt

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2316,6 +2316,9 @@ searchpos({pattern} [, {flags} [, {stopline} [, {timeout}]]])
23162316
server2client({clientid}, {string})
23172317
Number send reply string
23182318
serverlist() String get a list of available servers
2319+
setbufline( {expr}, {lnum}, {line})
2320+
Number set line {lnum} to {line} in buffer
2321+
{expr}
23192322
setbufvar({expr}, {varname}, {val})
23202323
none set {varname} in buffer {expr} to {val}
23212324
setcharsearch({dict}) Dict set character search from {dict}
@@ -6858,6 +6861,19 @@ serverlist() *serverlist()*
68586861
Example: >
68596862
:echo serverlist()
68606863
<
6864+
setbufline({expr}, {lnum}, {text}) *setbufline()*
6865+
Set line {lnum} to {text} in buffer {expr}. To insert
6866+
lines use |append()|.
6867+
6868+
For the use of {expr}, see |bufname()| above.
6869+
6870+
{lnum} is used like with |setline()|.
6871+
This works like |setline()| for the specified buffer.
6872+
On success 0 is returned, on failure 1 is returned.
6873+
6874+
If {expr} is not a valid buffer or {lnum} is not valid, an
6875+
error message is given.
6876+
68616877
setbufvar({expr}, {varname}, {val}) *setbufvar()*
68626878
Set option or local variable {varname} in buffer {expr} to
68636879
{val}.
@@ -6926,13 +6942,19 @@ setfperm({fname}, {mode}) *setfperm()* *chmod*
69266942

69276943
setline({lnum}, {text}) *setline()*
69286944
Set line {lnum} of the current buffer to {text}. To insert
6929-
lines use |append()|.
6945+
lines use |append()|. To set lines in another buffer use
6946+
|setbufline()|.
6947+
69306948
{lnum} is used like with |getline()|.
69316949
When {lnum} is just below the last line the {text} will be
69326950
added as a new line.
6951+
69336952
If this succeeds, 0 is returned. If this fails (most likely
6934-
because {lnum} is invalid) 1 is returned. Example: >
6953+
because {lnum} is invalid) 1 is returned.
6954+
6955+
Example: >
69356956
:call setline(5, strftime("%c"))
6957+
69366958
< When {text} is a |List| then line {lnum} and following lines
69376959
will be set to the items in the list. Example: >
69386960
:call setline(5, ['aaa', 'bbb', 'ccc'])

src/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2122,6 +2122,7 @@ test_arglist \
21222122
test_autocmd \
21232123
test_backspace_opt \
21242124
test_breakindent \
2125+
test_bufline \
21252126
test_bufwintabinfo \
21262127
test_cd \
21272128
test_cdo \

src/evalfunc.c

Lines changed: 113 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
328328
static void f_searchpos(typval_T *argvars, typval_T *rettv);
329329
static void f_server2client(typval_T *argvars, typval_T *rettv);
330330
static void f_serverlist(typval_T *argvars, typval_T *rettv);
331+
static void f_setbufline(typval_T *argvars, typval_T *rettv);
331332
static void f_setbufvar(typval_T *argvars, typval_T *rettv);
332333
static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
333334
static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
@@ -764,6 +765,7 @@ static struct fst
764765
{"searchpos", 1, 4, f_searchpos},
765766
{"server2client", 2, 2, f_server2client},
766767
{"serverlist", 0, 0, f_serverlist},
768+
{"setbufline", 3, 3, f_setbufline},
767769
{"setbufvar", 3, 3, f_setbufvar},
768770
{"setcharsearch", 1, 1, f_setcharsearch},
769771
{"setcmdpos", 1, 1, f_setcmdpos},
@@ -9867,6 +9869,115 @@ f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
98679869
rettv->vval.v_string = r;
98689870
}
98699871

9872+
/*
9873+
* Set line or list of lines in buffer "buf".
9874+
*/
9875+
static void
9876+
set_buffer_lines(buf_T *buf, linenr_T lnum, typval_T *lines, typval_T *rettv)
9877+
{
9878+
char_u *line = NULL;
9879+
list_T *l = NULL;
9880+
listitem_T *li = NULL;
9881+
long added = 0;
9882+
linenr_T lcount;
9883+
buf_T *curbuf_save;
9884+
int is_curbuf = buf == curbuf;
9885+
9886+
if (buf == NULL || buf->b_ml.ml_mfp == NULL || lnum < 1)
9887+
{
9888+
rettv->vval.v_number = 1; /* FAIL */
9889+
return;
9890+
}
9891+
9892+
curbuf_save = curbuf;
9893+
curbuf = buf;
9894+
9895+
lcount = curbuf->b_ml.ml_line_count;
9896+
9897+
if (lines->v_type == VAR_LIST)
9898+
{
9899+
l = lines->vval.v_list;
9900+
li = l->lv_first;
9901+
}
9902+
else
9903+
line = get_tv_string_chk(lines);
9904+
9905+
/* default result is zero == OK */
9906+
for (;;)
9907+
{
9908+
if (l != NULL)
9909+
{
9910+
/* list argument, get next string */
9911+
if (li == NULL)
9912+
break;
9913+
line = get_tv_string_chk(&li->li_tv);
9914+
li = li->li_next;
9915+
}
9916+
9917+
rettv->vval.v_number = 1; /* FAIL */
9918+
if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
9919+
break;
9920+
9921+
/* When coming here from Insert mode, sync undo, so that this can be
9922+
* undone separately from what was previously inserted. */
9923+
if (u_sync_once == 2)
9924+
{
9925+
u_sync_once = 1; /* notify that u_sync() was called */
9926+
u_sync(TRUE);
9927+
}
9928+
9929+
if (lnum <= curbuf->b_ml.ml_line_count)
9930+
{
9931+
/* existing line, replace it */
9932+
if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
9933+
{
9934+
changed_bytes(lnum, 0);
9935+
if (is_curbuf && lnum == curwin->w_cursor.lnum)
9936+
check_cursor_col();
9937+
rettv->vval.v_number = 0; /* OK */
9938+
}
9939+
}
9940+
else if (added > 0 || u_save(lnum - 1, lnum) == OK)
9941+
{
9942+
/* lnum is one past the last line, append the line */
9943+
++added;
9944+
if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
9945+
rettv->vval.v_number = 0; /* OK */
9946+
}
9947+
9948+
if (l == NULL) /* only one string argument */
9949+
break;
9950+
++lnum;
9951+
}
9952+
9953+
if (added > 0)
9954+
appended_lines_mark(lcount, added);
9955+
9956+
curbuf = curbuf_save;
9957+
}
9958+
9959+
/*
9960+
* "setbufline()" function
9961+
*/
9962+
static void
9963+
f_setbufline(argvars, rettv)
9964+
typval_T *argvars;
9965+
typval_T *rettv;
9966+
{
9967+
linenr_T lnum;
9968+
buf_T *buf;
9969+
9970+
buf = get_buf_tv(&argvars[0], FALSE);
9971+
if (buf == NULL)
9972+
rettv->vval.v_number = 1; /* FAIL */
9973+
else
9974+
{
9975+
lnum = get_tv_lnum_buf(&argvars[1], buf);
9976+
9977+
set_buffer_lines(buf, lnum, &argvars[2], rettv);
9978+
}
9979+
}
9980+
98709981
/*
98719982
* "setbufvar()" function
98729983
*/
@@ -10021,72 +10132,9 @@ f_setfperm(typval_T *argvars, typval_T *rettv)
1002110132
static void
1002210133
f_setline(typval_T *argvars, typval_T *rettv)
1002310134
{
10024-
linenr_T lnum;
10025-
char_u *line = NULL;
10026-
list_T *l = NULL;
10027-
listitem_T *li = NULL;
10028-
long added = 0;
10029-
linenr_T lcount = curbuf->b_ml.ml_line_count;
10030-
10031-
lnum = get_tv_lnum(&argvars[0]);
10032-
if (argvars[1].v_type == VAR_LIST)
10033-
{
10034-
l = argvars[1].vval.v_list;
10035-
li = l->lv_first;
10036-
}
10037-
else
10038-
line = get_tv_string_chk(&argvars[1]);
10039-
10040-
/* default result is zero == OK */
10041-
for (;;)
10042-
{
10043-
if (l != NULL)
10044-
{
10045-
/* list argument, get next string */
10046-
if (li == NULL)
10047-
break;
10048-
line = get_tv_string_chk(&li->li_tv);
10049-
li = li->li_next;
10050-
}
10135+
linenr_T lnum = get_tv_lnum(&argvars[0]);
1005110136

10052-
rettv->vval.v_number = 1; /* FAIL */
10053-
if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
10054-
break;
10055-
10056-
/* When coming here from Insert mode, sync undo, so that this can be
10057-
* undone separately from what was previously inserted. */
10058-
if (u_sync_once == 2)
10059-
{
10060-
u_sync_once = 1; /* notify that u_sync() was called */
10061-
u_sync(TRUE);
10062-
}
10063-
10064-
if (lnum <= curbuf->b_ml.ml_line_count)
10065-
{
10066-
/* existing line, replace it */
10067-
if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
10068-
{
10069-
changed_bytes(lnum, 0);
10070-
if (lnum == curwin->w_cursor.lnum)
10071-
check_cursor_col();
10072-
rettv->vval.v_number = 0; /* OK */
10073-
}
10074-
}
10075-
else if (added > 0 || u_save(lnum - 1, lnum) == OK)
10076-
{
10077-
/* lnum is one past the last line, append the line */
10078-
++added;
10079-
if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
10080-
rettv->vval.v_number = 0; /* OK */
10081-
}
10082-
10083-
if (l == NULL) /* only one string argument */
10084-
break;
10085-
++lnum;
10086-
}
10087-
10088-
if (added > 0)
10089-
appended_lines_mark(lcount, added);
10137+
set_buffer_lines(curbuf, lnum, &argvars[1], rettv);
1009010138
}
1009110139

1009210140
static void set_qf_ll_list(win_T *wp, typval_T *list_arg, typval_T *action_arg, typval_T *what_arg, typval_T *rettv);

src/testdir/test_alot.vim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
set belloff=all
55
source test_assign.vim
6+
source test_bufline.vim
67
source test_cd.vim
78
source test_changedtick.vim
89
source test_cursor_func.vim

src/testdir/test_bufline.vim

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
" Tests for setbufline() and getbufline()
2+
3+
func Test_setbufline_getbufline()
4+
new
5+
let b = bufnr('%')
6+
hide
7+
call assert_equal(0, setbufline(b, 1, ['foo', 'bar']))
8+
call assert_equal(['foo'], getbufline(b, 1))
9+
call assert_equal(['bar'], getbufline(b, 2))
10+
call assert_equal(['foo', 'bar'], getbufline(b, 1, 2))
11+
exe "bd!" b
12+
call assert_equal([], getbufline(b, 1, 2))
13+
14+
split Xtest
15+
call setline(1, ['a', 'b', 'c'])
16+
let b = bufnr('%')
17+
wincmd w
18+
call assert_equal(1, setbufline(b, 5, ['x']))
19+
call assert_equal(1, setbufline(1234, 1, ['x']))
20+
call assert_equal(0, setbufline(b, 4, ['d', 'e']))
21+
call assert_equal(['c'], getbufline(b, 3))
22+
call assert_equal(['d'], getbufline(b, 4))
23+
call assert_equal(['e'], getbufline(b, 5))
24+
call assert_equal([], getbufline(b, 6))
25+
exe "bwipe! " . b
26+
endfunc

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,8 @@ static char *(features[]) =
769769

770770
static int included_patches[] =
771771
{ /* Add new patch number below this line */
772+
/**/
773+
1039,
772774
/**/
773775
1038,
774776
/**/

0 commit comments

Comments
 (0)